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