From a2346ab4b39774bc0f6d15d502ed9e7ccaababdc Mon Sep 17 00:00:00 2001 From: springmin Date: Mon, 31 Aug 2026 00:03:59 +0800 Subject: [PATCH] Add linux-ohos (HarmonyOS) build infrastructure --- eng/RuntimeIdentifier.props | 4 +- eng/Subsets.props | 10 +++-- eng/build.sh | 11 ++++-- eng/liveBuilds.targets | 1 + eng/native/build-commons.sh | 41 ++++++++++++++++++-- eng/native/configurecompiler.cmake | 17 ++++++++ eng/native/configureplatform.cmake | 11 ++++++ eng/native/configuretools.cmake | 24 ++++++++++-- eng/native/gen-buildsys.sh | 7 +++- src/coreclr/clr.featuredefines.props | 2 +- src/coreclr/runtime.proj | 1 + src/native/corehost/corehost.proj | 1 + src/native/libs/System.Native/CMakeLists.txt | 2 +- src/native/libs/build-native.proj | 1 + src/native/libs/build-native.sh | 2 +- 15 files changed, 116 insertions(+), 19 deletions(-) diff --git a/eng/RuntimeIdentifier.props b/eng/RuntimeIdentifier.props index a3c396d8e6b6c7..86a42ce61f074c 100644 --- a/eng/RuntimeIdentifier.props +++ b/eng/RuntimeIdentifier.props @@ -19,6 +19,7 @@ linux-musl linux-bionic + linux-ohos $(PortableOS)-$(TargetArchitecture) @@ -50,7 +51,8 @@ true true true - true + true + true true true true diff --git a/eng/Subsets.props b/eng/Subsets.props index d7b4c953cd9f73..9f320412de2f65 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -56,7 +56,7 @@ true <_UseNativeAotForComponentsCrossOS Condition="'$(CrossBuild)' == 'true' and '$(_hostArchitecture)' == '$(_targetArchitecture)' and '$(_hostOS)' != 'windows'">true - true + true @@ -77,6 +77,9 @@ clr+libs+host+packs clr.nativeaotruntime+clr.nativeaotlibs+mono+libs+host+packs clr.nativeaotruntime+clr.nativeaotlibs+libs+packs + clr.nativeaotruntime+clr.nativeaotlibs+clr+mono+libs+host+packs + clr.nativeaotruntime+clr.nativeaotlibs+clr+libs+host+packs + clr.nativeaotruntime+clr.nativeaotlibs+mono+libs+host+packs clr+libs+tools+host+packs clr+libs+tools+host+packs @@ -384,8 +387,9 @@ --> - <_BuildAnyCrossArch Condition="('$(CrossBuild)' == 'true' or '$(BuildArchitecture)' != '$(TargetArchitecture)' or '$(HostOS)' != '$(TargetOS)' or '$(TargetsLinuxBionic)' == 'true' or '$(EnableNativeSanitizers)' != '')">true + It always targets the bionic libc via the NDK though, so host tools must be built separately. + linux-ohos (HarmonyOS) similarly reports TargetOS as 'linux' and uses its own NDK toolchain. --> + <_BuildAnyCrossArch Condition="('$(CrossBuild)' == 'true' or '$(BuildArchitecture)' != '$(TargetArchitecture)' or '$(HostOS)' != '$(TargetOS)' or '$(TargetsLinuxBionic)' == 'true' or '$(TargetOpenHarmony)' == 'true' or '$(EnableNativeSanitizers)' != '')">true <_BuildCrossComponents Condition="$(_subset.Contains('+clr.crossarchtools+'))">true <_BuildCrossComponents Condition="'$(ClrRuntimeBuildSubsets)' != '' and ('$(PrimaryRuntimeFlavor)' == 'CoreCLR' or '$(TargetsMobile)' == 'true')">true <_CrossBitwidthBuild Condition="'$(BuildArchitecture)' == 'x64' and ('$(TargetArchitecture)' == 'x86' or '$(TargetArchitecture)' == 'arm')">true diff --git a/eng/build.sh b/eng/build.sh index b4496e0bc362f1..c21ae714389875 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -32,7 +32,7 @@ usage() echo " [Default: Debug]" echo " --os Target operating system: windows, linux, freebsd, osx, maccatalyst, tvos," echo " tvossimulator, ios, iossimulator, android, browser, wasi, netbsd, illumos, solaris" - echo " linux-musl, linux-bionic, tizen, or haiku." + echo " linux-musl, linux-bionic, linux-ohos, tizen, or haiku." echo " [Default: Your machine's OS.]" echo " --targetrid Optional argument that overrides the target rid name." echo " --projects Project or solution file(s) to build." @@ -146,8 +146,9 @@ initDistroRid() local isCrossBuild="$3" # Only pass ROOTFS_DIR if __DoCrossArchBuild is specified and the current platform is not an Apple platform (that doesn't use rootfs) - if [[ $isCrossBuild == 1 && "$targetOs" != "osx" && "$targetOs" != "android" && "$targetOs" != "ios" && "$targetOs" != "iossimulator" && "$targetOs" != "tvos" && "$targetOs" != "tvossimulator" && "$targetOs" != "maccatalyst" ]]; then - passedRootfsDir=${ROOTFS_DIR} + # HarmonyOS uses its NDK toolchain, so no rootfs is required either. + if [[ $isCrossBuild == 1 && "$targetOs" != "osx" && "$targetOs" != "android" && "$targetOs" != "ios" && "$targetOs" != "iossimulator" && "$targetOs" != "tvos" && "$targetOs" != "tvossimulator" && "$targetOs" != "maccatalyst" && "${__PortableTargetOS:-}" != "linux-ohos" ]]; then + passedRootfsDir=${ROOTFS_DIR:-} fi initDistroRidGlobal "${targetOs}" "${targetArch}" "${passedRootfsDir}" } @@ -310,6 +311,10 @@ while [[ $# -gt 0 ]]; do os="linux" __PortableTargetOS=linux-musl ;; + linux-ohos) + os="linux" + __PortableTargetOS=linux-ohos + ;; haiku) os="haiku" ;; *) diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets index e494ca933bdbea..b56886ca5e8569 100644 --- a/eng/liveBuilds.targets +++ b/eng/liveBuilds.targets @@ -15,6 +15,7 @@ $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'artifacts', 'bin', 'coreclr', '$(TargetOS).$(TargetArchitecture).$(CoreCLRConfiguration)')) + $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'artifacts', 'bin', 'coreclr', 'linux-ohos.$(TargetArchitecture).$(CoreCLRConfiguration)')) $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'artifacts', 'bin', 'mono', '$(TargetOS).$(TargetArchitecture).$(MonoConfiguration)')) $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'artifacts')) $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'artifacts')) diff --git a/eng/native/build-commons.sh b/eng/native/build-commons.sh index fdf156b16fec2e..6409a7efb16728 100755 --- a/eng/native/build-commons.sh +++ b/eng/native/build-commons.sh @@ -7,7 +7,7 @@ initTargetDistroRid() local passedRootfsDir="" # Only pass ROOTFS_DIR if cross is specified and the target platform is not Darwin that doesn't use rootfs - if [[ "$__CrossBuild" == 1 && "$platform" != "darwin" ]]; then + if [[ "$__CrossBuild" == 1 && "$platform" != "darwin" && "$__TargetOS" != "linux-ohos" ]]; then passedRootfsDir="$ROOTFS_DIR" fi @@ -137,6 +137,38 @@ build_native() echo "Error: Unknown Android architecture $hostArch." exit 1 fi + elif [[ "$targetOS" == linux-ohos ]]; then + # HarmonyOS (OpenHarmony) NDK-style toolchain. The OHOS NDK provides its + # own CMake toolchain file (ohos.toolchain.cmake) which sets CMAKE_SYSTEM_NAME=OHOS + # and selects the aarch64/arm/x86_64 linux-ohos clang wrappers + sysroot. + if [[ -z "$OHOS_NDK_HOME" ]]; then + echo "Error: You need to set the OHOS_NDK_HOME environment variable pointing to the HarmonyOS NDK root." + exit 1 + fi + + local ohosToolchainFile="$OHOS_NDK_HOME/native/build/cmake/ohos.toolchain.cmake" + if [[ ! -f "$ohosToolchainFile" ]]; then + echo "Error: OHOS CMake toolchain file not found at $ohosToolchainFile. Verify OHOS_NDK_HOME." + exit 1 + fi + + cmakeArgs="-DCMAKE_TOOLCHAIN_FILE=$ohosToolchainFile $cmakeArgs" + cmakeArgs="-DOHOS_NDK_HOME=$OHOS_NDK_HOME $cmakeArgs" + cmakeArgs="-C $__RepoRootDir/eng/native/tryrun.cmake $cmakeArgs" + + # Don't try to set CC/CXX in init-compiler.sh - it's handled in ohos.toolchain.cmake already + __Compiler="default" + + if [[ "$hostArch" == arm64 ]]; then + cmakeArgs="-DOHOS_ARCH=arm64-v8a $cmakeArgs" + elif [[ "$hostArch" == arm ]]; then + cmakeArgs="-DOHOS_ARCH=armeabi-v7a $cmakeArgs" + elif [[ "$hostArch" == x64 ]]; then + cmakeArgs="-DOHOS_ARCH=x86_64 $cmakeArgs" + else + echo "Error: Unknown OHOS architecture $hostArch." + exit 1 + fi elif [[ "$targetOS" == iossimulator ]]; then cmakeArgs="-C $__RepoRootDir/eng/native/tryrun_ios_tvos.cmake $cmakeArgs" @@ -596,6 +628,9 @@ elif [[ "$__TargetOS" == osx || "$__TargetOS" == maccatalyst ]]; then elif [[ "$__TargetOS" == android ]]; then # nothing to do here true +elif [[ "$__TargetOS" == linux-ohos ]]; then + # HarmonyOS uses its NDK toolchain, no rootfs required + true else __CMakeArgs="-DFEATURE_DISTRO_AGNOSTIC_SSL=$__PortableBuild $__CMakeArgs" fi @@ -604,8 +639,8 @@ fi if [[ "$__CrossBuild" == 1 ]]; then CROSSCOMPILE=1 export CROSSCOMPILE - # Darwin that doesn't use rootfs - if [[ -z "$ROOTFS_DIR" && "$platform" != "darwin" ]]; then + # Darwin that doesn't use rootfs; HarmonyOS uses its NDK toolchain + if [[ -z "$ROOTFS_DIR" && "$platform" != "darwin" && "$__TargetOS" != "linux-ohos" ]]; then ROOTFS_DIR="$__RepoRootDir/.tools/rootfs/$__TargetArch" export ROOTFS_DIR fi diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake index bc5fcb1733acb7..55b1bfb309afbf 100644 --- a/eng/native/configurecompiler.cmake +++ b/eng/native/configurecompiler.cmake @@ -653,6 +653,20 @@ if (CLR_CMAKE_HOST_UNIX OR CLR_CMAKE_HOST_WASI) add_compile_options(-fstack-protector-strong) endif() + if(CLR_CMAKE_HOST_OPENHARMONY) + # The OHOS NDK toolchain injects --gcc-toolchain (via CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN) + # which clang reports as unused; silence it (in CMAKE_C_FLAGS so try_compile checks + # inherit it) so -Werror doesn't fail the build. Applies to assembly too. + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Qunused-arguments") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments") + set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Qunused-arguments") + # The arm64 asm helpers access t_ThreadStatics/t_runtime_thread_locals via TLS + # descriptors; the C++ definitions must use native (non-emulated) TLS with the + # global-dynamic model to match. + add_compile_options(-fno-emulated-tls) + add_compile_options(-ftls-model=global-dynamic) + endif() + # Suppress warnings-as-errors in release branches to reduce servicing churn if (PRERELEASE) add_compile_options(-Werror) @@ -845,6 +859,9 @@ if(CLR_CMAKE_TARGET_UNIX) if(CLR_CMAKE_TARGET_LINUX_MUSL) add_compile_definitions($<$>>:TARGET_LINUX_MUSL>) endif() + if(CLR_CMAKE_TARGET_OPENHARMONY) + add_compile_definitions($<$>>:TARGET_OPENHARMONY>) + endif() if(CLR_CMAKE_TARGET_ANDROID) add_compile_definitions($<$>>:TARGET_ANDROID>) endif() diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake index 2ccced093f6b38..f04fba710b8cae 100644 --- a/eng/native/configureplatform.cmake +++ b/eng/native/configureplatform.cmake @@ -11,6 +11,13 @@ set(PRERELEASE 1) #---------------------------------------- set(CLR_CMAKE_HOST_OS ${CMAKE_SYSTEM_NAME}) string(TOLOWER ${CLR_CMAKE_HOST_OS} CLR_CMAKE_HOST_OS) +# HarmonyOS (OpenHarmony) uses the OHOS NDK CMake toolchain which sets +# CMAKE_SYSTEM_NAME=OHOS. Its libc is musl-based, so treat it as a linux/musl target. +if(CLR_CMAKE_HOST_OS STREQUAL ohos) + set(CLR_CMAKE_HOST_OS linux) + set(CLR_CMAKE_HOST_LINUX_MUSL 1) + set(CLR_CMAKE_HOST_OPENHARMONY 1) +endif() if(CLR_CMAKE_HOST_OS STREQUAL linux) set(CLR_CMAKE_HOST_UNIX 1) if(CLR_CROSS_COMPONENTS_BUILD) @@ -357,6 +364,10 @@ if(CLR_CMAKE_HOST_LINUX_MUSL OR CLR_CMAKE_TARGET_OS STREQUAL alpine) set(CLR_CMAKE_TARGET_LINUX_MUSL 1) endif(CLR_CMAKE_HOST_LINUX_MUSL OR CLR_CMAKE_TARGET_OS STREQUAL alpine) +if(CLR_CMAKE_HOST_OPENHARMONY) + set(CLR_CMAKE_TARGET_OPENHARMONY 1) +endif() + macro(set_cache_value) set(${ARGV0} ${ARGV1} CACHE STRING "Result from TRY_RUN" FORCE) set(${ARGV0}__TRYRUN_OUTPUT "dummy output" CACHE STRING "Output from TRY_RUN" FORCE) diff --git a/eng/native/configuretools.cmake b/eng/native/configuretools.cmake index 16d039acc39830..6d3fa2c59799d5 100644 --- a/eng/native/configuretools.cmake +++ b/eng/native/configuretools.cmake @@ -28,11 +28,27 @@ if(NOT WIN32 AND NOT CLR_CMAKE_TARGET_BROWSER AND NOT CLR_CMAKE_TARGET_WASI) return() endif() + # For NDK-style toolchains (HarmonyOS) the compiler lives outside PATH. + # Hint find_program at the compiler's directory so tools like llvm-ar/nm are located. + # Guarded to OHOS only so other platforms keep their existing lookup behavior. + if(CLR_CMAKE_HOST_OPENHARMONY) + get_filename_component(CLR_COMPILER_DIR "${CMAKE_C_COMPILER}" DIRECTORY) + endif() + unset(EXEC_LOCATION_${exec} CACHE) - find_program(EXEC_LOCATION_${exec} - NAMES - "${TOOLSET_PREFIX}${exec}${CLR_CMAKE_COMPILER_FILE_NAME_VERSION}" - "${TOOLSET_PREFIX}${exec}") + if(CLR_CMAKE_HOST_OPENHARMONY) + find_program(EXEC_LOCATION_${exec} + NAMES + "${TOOLSET_PREFIX}${exec}${CLR_CMAKE_COMPILER_FILE_NAME_VERSION}" + "${TOOLSET_PREFIX}${exec}" + HINTS + "${CLR_COMPILER_DIR}") + else() + find_program(EXEC_LOCATION_${exec} + NAMES + "${TOOLSET_PREFIX}${exec}${CLR_CMAKE_COMPILER_FILE_NAME_VERSION}" + "${TOOLSET_PREFIX}${exec}") + endif() if (required AND EXEC_LOCATION_${exec} STREQUAL "EXEC_LOCATION_${exec}-NOTFOUND") message(FATAL_ERROR "Unable to find toolchain executable. Name: '${exec}', Prefix: '${TOOLSET_PREFIX}'") diff --git a/eng/native/gen-buildsys.sh b/eng/native/gen-buildsys.sh index 72b82a136ce17d..63c005859df273 100755 --- a/eng/native/gen-buildsys.sh +++ b/eng/native/gen-buildsys.sh @@ -63,8 +63,8 @@ done cmake_extra_defines= if [[ "$CROSSCOMPILE" == "1" ]]; then platform="$(uname -s | tr '[:upper:]' '[:lower:]')" - # OSX doesn't use rootfs - if ! [[ -n "$ROOTFS_DIR" || "$platform" == "darwin" ]]; then + # OSX doesn't use rootfs; HarmonyOS uses its NDK toolchain + if ! [[ -n "$ROOTFS_DIR" || "$platform" == "darwin" || "$target_os" == "linux-ohos" ]]; then echo "ROOTFS_DIR not set for crosscompile" exit 1 fi @@ -76,6 +76,9 @@ if [[ "$CROSSCOMPILE" == "1" ]]; then if [[ "$platform" == "darwin" ]]; then cmake_extra_defines="$cmake_extra_defines -DCMAKE_SYSTEM_NAME=Darwin" + elif [[ "$target_os" == "linux-ohos" ]]; then + # HarmonyOS NDK toolchain is injected by build-commons.sh; do not override it. + true else cmake_extra_defines="$cmake_extra_defines -DCMAKE_TOOLCHAIN_FILE=$scriptroot/../common/cross/toolchain.cmake" fi diff --git a/src/coreclr/clr.featuredefines.props b/src/coreclr/clr.featuredefines.props index 9592c1919a8efa..f9ea77e08470a3 100644 --- a/src/coreclr/clr.featuredefines.props +++ b/src/coreclr/clr.featuredefines.props @@ -41,7 +41,7 @@ - true + true true diff --git a/src/coreclr/runtime.proj b/src/coreclr/runtime.proj index b20e9a35fc87ab..8cfba3fe01f998 100644 --- a/src/coreclr/runtime.proj +++ b/src/coreclr/runtime.proj @@ -3,6 +3,7 @@ <_BuildNativeTargetOS>$(TargetOS) <_BuildNativeTargetOS Condition="'$(TargetsLinuxBionic)' == 'true'">linux-bionic + <_BuildNativeTargetOS Condition="'$(TargetOpenHarmony)' == 'true'">linux-ohos true GetPgoDataPackagePath $(BuildRuntimeDependsOnTargets);InitializeSourceControlInformationFromSourceControlManager diff --git a/src/native/corehost/corehost.proj b/src/native/corehost/corehost.proj index 05a479acd8884b..118ecf080f422f 100644 --- a/src/native/corehost/corehost.proj +++ b/src/native/corehost/corehost.proj @@ -62,6 +62,7 @@ <_CoreHostUnixTargetOS>$(TargetOS) <_CoreHostUnixTargetOS Condition="'$(TargetsLinuxBionic)' == 'true'">linux-bionic + <_CoreHostUnixTargetOS Condition="'$(TargetOpenHarmony)' == 'true'">linux-ohos $(Configuration) $(TargetArchitecture) -commithash "$([MSBuild]::ValueOrDefault('$(SourceRevisionId)', 'N/A'))" -os $(_CoreHostUnixTargetOS) $(BuildArgs) -cmakeargs "-DVERSION_FILE_PATH=$(NativeVersionFile)" diff --git a/src/native/libs/System.Native/CMakeLists.txt b/src/native/libs/System.Native/CMakeLists.txt index 5930703021940b..8273eb07010019 100644 --- a/src/native/libs/System.Native/CMakeLists.txt +++ b/src/native/libs/System.Native/CMakeLists.txt @@ -57,7 +57,7 @@ else() # WASI ) endif() -if (CLR_CMAKE_TARGET_APPLE OR CLR_CMAKE_TARGET_ANDROID OR CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI OR CLR_CMAKE_TARGET_OPENBSD OR CLR_CMAKE_TARGET_HAIKU) +if (CLR_CMAKE_TARGET_APPLE OR CLR_CMAKE_TARGET_ANDROID OR CLR_CMAKE_TARGET_BROWSER OR CLR_CMAKE_TARGET_WASI OR CLR_CMAKE_TARGET_OPENBSD OR CLR_CMAKE_TARGET_HAIKU OR CLR_CMAKE_TARGET_OPENHARMONY) # These platforms do not support robust mutexes. # Keep an OS list instead of CMake configure checks since we also need to synchronize this with # the compile-time guards on the managed code side at diff --git a/src/native/libs/build-native.proj b/src/native/libs/build-native.proj index ac7308eb4e0f25..c202a1400572ac 100644 --- a/src/native/libs/build-native.proj +++ b/src/native/libs/build-native.proj @@ -9,6 +9,7 @@ .NET Runtime <_BuildNativeTargetOS>$(TargetOS) <_BuildNativeTargetOS Condition="'$(TargetsLinuxBionic)' == 'true'">linux-bionic + <_BuildNativeTargetOS Condition="'$(TargetOpenHarmony)' == 'true'">linux-ohos <_BuildNativeOutConfig>$(NetCoreAppCurrent)-$(TargetOS)-$(Configuration)-$(TargetArchitecture) <_BuildNativeArgs>$(TargetArchitecture) $(Configuration) outconfig $(_BuildNativeOutConfig) -os $(_BuildNativeTargetOS) <_BuildNativeArgs Condition="'$(EnableNativeSanitizers)' != ''">$(_BuildNativeArgs) -fsanitize=$(EnableNativeSanitizers) diff --git a/src/native/libs/build-native.sh b/src/native/libs/build-native.sh index 05b77499d7d40a..a6e850daa5873b 100755 --- a/src/native/libs/build-native.sh +++ b/src/native/libs/build-native.sh @@ -58,7 +58,7 @@ else __CMakeArgs="-DFEATURE_DISTRO_AGNOSTIC_SSL=$__PortableBuild $__CMakeArgs" __CMakeArgs="-DCMAKE_STATIC_LIB_LINK=$__StaticLibLink $__CMakeArgs" - if [[ "$__TargetOS" != linux-bionic && "$__TargetArch" != x86 && "$__TargetArch" != x64 && "$__TargetArch" != "$__HostArch" ]]; then + if [[ "$__TargetOS" != linux-bionic && "$__TargetOS" != linux-ohos && "$__TargetArch" != x86 && "$__TargetArch" != x64 && "$__TargetArch" != "$__HostArch" ]]; then __CrossBuild=1 echo "Set CrossBuild for $__TargetArch build" fi