diff --git a/eng/RuntimeIdentifier.props b/eng/RuntimeIdentifier.props
index a3c396d8e6b6c7..7a85c173a61d6a 100644
--- a/eng/RuntimeIdentifier.props
+++ b/eng/RuntimeIdentifier.props
@@ -8,7 +8,9 @@
+ And, for flavors of Linux, like 'linux-musl' and 'linux-bionic', TargetOS is 'linux'.
+ ohos is an exception: its RID is kernel-agnostic, so TargetOS is 'ohos' (not 'linux'),
+ and it opts into the Linux family flags explicitly below. -->
$(TargetOS.ToLowerInvariant())
win
@@ -19,6 +21,7 @@
linux-musl
linux-bionic
+ ohos
$(PortableOS)-$(TargetArchitecture)
@@ -47,10 +50,13 @@
true
true
true
- true
+
+ true
true
true
- true
+ true
+ true
true
true
true
diff --git a/eng/Subsets.props b/eng/Subsets.props
index 898741f170e185..3c20c2eb937d59 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,8 @@
clr+libs+host+packs
clr.nativeaotruntime+clr.nativeaotlibs+mono+libs+host+packs
clr.nativeaotruntime+clr.nativeaotlibs+libs+packs
+
+ clr.nativeaotruntime+clr.nativeaotlibs+clr+libs+host+packs
clr+libs+tools+host+packs
clr+libs+tools+host+packs
diff --git a/eng/build.sh b/eng/build.sh
index b4496e0bc362f1..f0b85a3f45c379 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, 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}
+ # OpenHarmony 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:-}" != "ohos" ]]; then
+ passedRootfsDir=${ROOTFS_DIR:-}
fi
initDistroRidGlobal "${targetOs}" "${targetArch}" "${passedRootfsDir}"
}
@@ -310,6 +311,10 @@ while [[ $# -gt 0 ]]; do
os="linux"
__PortableTargetOS=linux-musl
;;
+ ohos)
+ os="ohos"
+ __PortableTargetOS=ohos
+ ;;
haiku)
os="haiku" ;;
*)
@@ -626,6 +631,12 @@ export DOTNETSDK_ALLOW_TARGETING_PACK_CACHING=0
# In *proj files (XML docs), URL-encoded string are rendered in their decoded form.
cmakeargs="${cmakeargs// /%20}"
arguments+=("/p:TargetArchitecture=$arch" "/p:BuildArchitecture=$hostArch")
+# Propagate the portable target OS (e.g. 'ohos', 'linux-musl', 'linux-bionic') to MSBuild.
+# TargetOS stays 'linux' for these flavors; PortableOS in RuntimeIdentifier.props
+# derives from __PortableTargetOS, and downstream (packaging, live builds) relies on it.
+if [[ -n "${__PortableTargetOS:-}" ]]; then
+ arguments+=("/p:__PortableTargetOS=$__PortableTargetOS")
+fi
arguments+=("/p:CMakeArgs=\"$cmakeargs\"" ${extraargs[@]+"${extraargs[@]}"})
if [[ "$bootstrap" == "1" ]]; then
diff --git a/eng/native/build-commons.sh b/eng/native/build-commons.sh
index fdf156b16fec2e..657906c9353dbf 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" != "ohos" ]]; then
passedRootfsDir="$ROOTFS_DIR"
fi
@@ -137,6 +137,38 @@ build_native()
echo "Error: Unknown Android architecture $hostArch."
exit 1
fi
+ elif [[ "$targetOS" == ohos ]]; then
+ # 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 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 OpenHarmony 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" == ohos ]]; then
+ # OpenHarmony 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; OpenHarmony uses its NDK toolchain
+ if [[ -z "$ROOTFS_DIR" && "$platform" != "darwin" && "$__TargetOS" != "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..700e508c84f5f8 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)
+# 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..555c35f5ca035e 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 (OpenHarmony) 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..087353cd3feac0 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; OpenHarmony uses its NDK toolchain
+ if ! [[ -n "$ROOTFS_DIR" || "$platform" == "darwin" || "$target_os" == "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" == "ohos" ]]; then
+ # OpenHarmony 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/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.sh b/src/native/libs/build-native.sh
index 05b77499d7d40a..77a616cd9c0ec0 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" != ohos && "$__TargetArch" != x86 && "$__TargetArch" != x64 && "$__TargetArch" != "$__HostArch" ]]; then
__CrossBuild=1
echo "Set CrossBuild for $__TargetArch build"
fi