Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Haiku: add platform support #55803

Open
jessicah opened this issue Jul 16, 2021 · 159 comments
Open

Haiku: add platform support #55803

jessicah opened this issue Jul 16, 2021 · 159 comments
Labels
area-PAL-coreclr help wanted [up-for-grabs] Good issue for external contributors os-haiku
Milestone

Comments

@jessicah
Copy link

Opening an issue to track work on adding platform support for Haiku: https://www.haiku-os.org/.

Any tips on how cross-compiling should work would be appreciated. Am currently starting with './build.sh mono+libs -arch x64 -os haiku -c debug -cross, and slowly adding Haiku targets to build and about to start some work on adding platform support in src/libraries/Common/src/Interop`.

Thus far it hasn't required a functioning cross-compiler yet, have only just started.

@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged New issue has not been triaged by the area owner label Jul 16, 2021
@En3Tho
Copy link
Contributor

En3Tho commented Jul 16, 2021

What are benefits of having Haiku as an os target vs other os'es?

@am11
Copy link
Member

am11 commented Jul 16, 2021

Here is a quick list without debugging shell or cmake scripts / how-to-get-there steps (if you need to know something specific, i can comment it separately):

  1. add crossbuild toolchain support in: eng/common/cross/build-rootfs.sh
    and eng/common/cross/toolchain.cmake
  2. update eng/native/configure*.cmake files for compiler options under eng/native/ directory
  3. update groups with Calculate* labels in Directory.Build.props file at the root of this repo
  4. for mono, update src/mono/mono.proj, src/mono/CMakeLists.txt and src/mono/Directory.Build.props files

Then run eng/common/cross/build-rootfs haiku x64 to build the rootfs enviornment and ROOTFS_DIR=$(pwd)/.tools/x64 ./build.sh -cross -arch x64 -os haiku to get started with code-only changes. From time to time, you may need to update local configurations of projects being ported, but the aforementioned central configuration take care of most of the wiring.

Later on if you want to make a persistent environment, you can get a docker tag from https://github.com/dotnet/dotnet-buildtools-prereqs-docker, with rootfs at a fixed location: /crossrootfs/x64. We did this step for illumos/SmartOS very early to make development environment stateless and build recipe sharable with other community members.

@ghost ghost added this to Needs triage in Triage POD for Meta, Reflection, etc Jul 16, 2021
@jessicah
Copy link
Author

Thanks @am11, is mono+libs the right target to start with? Also, what's the difference between mono in this repo, and https://github.com/mono/mono?

@am11
Copy link
Member

am11 commented Jul 17, 2021

is mono+libs the right target to start with?

Yes, imo, after the common configurations are done, focusing first on mono and then libraries would be the fastest way to get .NET 6 working on Haiku. Going by git grep -i haiku, you can already tell there is some related code from the initial mono port in dotnet/runtime repo.

Later you can look into corehost (dontet(1)) to make the build binaries usable with .NET SDK etc. It would also make it much easier to then port coreclr runtime.

what's the difference between mono in this repo, and https://github.com/mono/mono?

mono/mono (OSS) aims to be compatible with .NET Framework 4.7 (closed source).
Mono subset (src/mono) in this repository started off as a port of same mono runtime (minus the legacy components of .NET Framework 4.7, which are not supported in .NET 5) and implements common runtime interface as src/coreclr. The initial focus was to support various targets including, but not limited to, Xamrian, Mobile and WebAssembly that coreclr does not support today.

The core .NET libraries in this repo are tested against both (coreclr and mono) runtime flavors. The goal is to make both runtimes drop-in replacements of each other, and they can (and do) overlap when it comes to platform targets. Officially the focus for runtime/src/mono so far has been on mobile-like targets, but mono RT built from this repo runs desktop apps just fine (to do that it currently requires two manual cp steps which hopefully may no longer be needed in the future 😁).

jessicah added a commit to jessicah/dotnet-runtime that referenced this issue Jul 19, 2021
@jessicah
Copy link
Author

jessicah commented Jul 19, 2021

@am11 Running into a weird issue with configuration in src/libraries/Native:

https://github.com/jessicah/dotnet-runtime/blob/haiku/src/libraries/Native/Unix/System.Globalization.Native/CMakeLists.txt#L22

  CMake Error at System.Globalization.Native/CMakeLists.txt:24 (message):
    Cannot find utypes.h, try installing libicu-dev (or the appropriate package
    for your platform)

It feels like it's not searching the configured sysroot. Invoking build.sh as follows: ROOTFS_DIR=/home/jessica/build/haiku-sysroot ./build.sh mono+libs -arch x64 -os haiku -c debug -cross --ninja.

jessica@homecloud:~/build/haiku-sysroot/boot/system/develop/headers$ find -name utypes.h
./unicode/utypes.h

Not really sure what I'm doing wrong. All the checks being run in configure.cmake appear to be invoking the Haiku cross-compiler correctly. Unfortunately I can't find a log that mentions the utype.h search. It's definitely for cross-compiling, as libicu-dev is installed on host Linux.

Logs in artifacts/obj/native/net6.0-Haiku-Debug-x64/CMakeFiles: https://gist.github.com/jessicah/7f8693f773d7ddec8c51f2df15da0221

Additionally, if I comment out the search and just hard code them as succeeding, then in configure.cmake, the checks for HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS and HAVE_SET_MAX_VARIABLE both compile and pass, so the sysroot is configured correctly for compile/link, just the builtin CMake functions are not working correctly.

@am11
Copy link
Member

am11 commented Jul 19, 2021

Could you try adding:

+++ eng/common/cross/toolchain.cmake
--- eng/common/cross/toolchain.cmake

elseif(CMAKE_SYSTEM_NAME STREQUAL "Haiku")
    set(CMAKE_SYSROOT "${CROSS_ROOTFS}")
+    include_directories(SYSTEM ${CROSS_ROOTFS}/boot/system/develop/headers)
+    set(CMAKE_SYSTEM_PREFIX_PATH "${CROSS_ROOTFS}")
else()

to see if it gives clean result. I remember having similar issue with ICU on illumos, and tweaking toolchain.cmake helped. Your observation is spot on, the flags and definitions used by cmake introspection are different than those used for the actual compilation. IIRC, that include_directories sets it for both.

@NattyNarwhal
Copy link
Contributor

I did the PAL port and (attempt at) Mono runtime stuff in mono/mono; ping me if you need me.

@jessicah
Copy link
Author

@am11 no luck, unfortunately :-/

@am11
Copy link
Member

am11 commented Jul 20, 2021

I think it is ok to continue with a workaround at least for now. :)

Additionally, if I comment out the search and just hard code them as succeeding, then in configure.cmake, the checks for HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS and HAVE_SET_MAX_VARIABLE both compile and pass, so the sysroot is configured correctly for compile/link, just the builtin CMake functions are not working correctly.

best place to do this hardcoding is eng/native/tryrun.cmake and set cache value. In case cmake tryrun is new to you, cmake invokes it basically before anything else (even cmake's own modules), which is why the custom way of platform detection (like /HaikuConfig.h in your case) is needed.

  • if the cmake check is based on static condition or existance of symbol or header, then we use set_cache_value($VAR_NAME 0) or set_cache_value($VAR_NAME 1)
    • as you notice in that file that this is normally not needed. usually it's misconfiguration if static analysis of header files or libraries is giving undesired results.
  • if the cmake check is based on try_compile, compiling and running a piece of code to identify something (which is not possible in cross-compilation), then we append _EXITCODE to $VAR_NAME.

@jessicah
Copy link
Author

Hacked my way further, but running into an issue with src/libraries/shims that I can't piece together from the project/build files:

/home/jessica/source/rt2/src/libraries/shims/manual/System.forwards.cs(8,88): error CS0234: The type or namespace name 'ZLibException' does not exist in the namespace 'System.IO.Compression' (are you missing an assembly reference?) [/home/jessica/source/rt2/src/libraries/shims/manual/System.csproj]
/home/jessica/source/rt2/src/libraries/shims/manual/System.forwards.cs(9,77): error CS0234: The type or namespace name 'CookieVariant' does not exist in the namespace 'System.Net' (are you missing an assembly reference?) [/home/jessica/source/rt2/src/libraries/shims/manual/System.csproj]
/home/jessica/source/rt2/src/libraries/shims/manual/System.forwards.cs(10,77): error CS0234: The type or namespace name 'PathList' does not exist in the namespace 'System.Net' (are you missing an assembly reference?) [/home/jessica/source/rt2/src/libraries/shims/manual/System.csproj]

@jessicah
Copy link
Author

@am11 With jessicah@10e4e8b it "finishes", but I'm not sure what I have :p

It seems like the mono build is targeted for Linux, although the .so files not related to mono are linked against the Haiku libraries. I'm guessing mono isn't configured to build for Haiku, and probably some other parts are like this too :-/

I'll have a deeper look into tryrun.cmake, perhaps this is the cause of CMake's find_path and friends failing...

@am11
Copy link
Member

am11 commented Jul 20, 2021

For mono, it would require a patch like a47b8dc (it used to be autoconf based, now mono build in this repo has been moved to cmake).

tryrun.cmake

usually i run the configure-only step natively on platform (like OpenIndiana for illumos) to collect all the expected configure values then run the same with cross toolchain on linux, the diff is what goes in the tryrun.cmake (minus a things which are optional, but it doesn't hurt to have the entire diff in).

@jessicah
Copy link
Author

jessicah commented Jul 20, 2021

A lot of that patch looks like fixes for building Illumos on Illumos, as most of these are HOST variables.

Anyway, I've just noticed this in the build output (the CMAKE variables it outpus), that I didn't see previously:

jessi@unbuntu:~/source/dotnet-runtime$ cat ../run
#!/bin/bash

ROOTFS_DIR=~/build/haiku-sysroot ./build.sh mono+libs -arch x64 -os haiku -c debug -cross --ninja

jessi@unbuntu:~/source/dotnet-runtime$ ../run
__DistroRid: haiku.r1-x64
  Determining projects to restore...
  Tool 'coverlet.console' (version '1.7.2') was restored. Available commands: coverlet
  Tool 'dotnet-reportgenerator-globaltool' (version '4.5.8') was restored. Available commands: reportgenerator
  Tool 'microsoft.dotnet.xharness.cli' (version '1.0.0-prerelease.21357.4') was restored. Available commands: xharness
  Tool 'microsoft.visualstudio.slngen.tool' (version '5.0.5') was restored. Available commands: slngen

  Restore was successful.
  All projects are up-to-date for restore.
  Determining projects to restore...
  All projects are up-to-date for restore.
  RuntimeConfigParser -> /home/jessi/source/dotnet-runtime/artifacts/bin/RuntimeConfigParser/Debug/net6.0/RuntimeConfigParser.dll
  JsonToItemsTaskFactory -> /home/jessi/source/dotnet-runtime/artifacts/bin/JsonToItemsTaskFactory/Debug/net472/JsonToItemsTaskFactory.dll
  RuntimeConfigParser -> /home/jessi/source/dotnet-runtime/artifacts/bin/RuntimeConfigParser/Debug/net472/RuntimeConfigParser.dll
  JsonToItemsTaskFactory -> /home/jessi/source/dotnet-runtime/artifacts/bin/JsonToItemsTaskFactory/Debug/net6.0/JsonToItemsTaskFactory.dll
  Microsoft.NET.Runtime.MonoTargets.Sdk -> /home/jessi/source/dotnet-runtime/artifacts/packages/Debug/Shipping/Microsoft.NET.Runtime.MonoTargets.Sdk.6.0.0-dev.nupkg
  Determining projects to restore...
  All projects are up-to-date for restore.
  The CMake command line is the same as the last run. Skipping running CMake configure.
  Running 'TARGET_BUILD_ARCH=x64 cmake --build . --target install --config Debug' in '/home/jessi/source/dotnet-runtime/artifacts/obj/mono/Haiku.x64.Debug/'
  [0/1] Re-running CMake...
  CMAKE_SYSTEM_NAME=Linux
  CMAKE_SYSTEM_VARIANT=
  CMAKE_SYSTEM_PROCESSOR=x86_64
  TARGET_ARCH=x86_64
  CMAKE_CROSSCOMPILING=FALSE
  -- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)
  -- Configuring done
  -- Generating done
  -- Build files have been written to: /home/jessi/source/dotnet-runtime/artifacts/obj/mono/Haiku.x64.Debug
  [0/1] Install the project...
  -- Install configuration: "Debug"
  Stripping debug symbols from /home/jessi/source/dotnet-runtime/artifacts/obj/mono/Haiku.x64.Debug/out/lib/libcoreclr.so
  System.Private.CoreLib.Generators -> /home/jessi/source/dotnet-runtime/artifacts/bin/System.Private.CoreLib.Generators/netstandard2.0-Debug/System.Private.CoreLib.Generators.dll
  System.Private.CoreLib -> /home/jessi/source/dotnet-runtime/artifacts/bin/mono/Haiku.x64.Debug/IL/System.Private.CoreLib.dll
  /home/jessi/source/dotnet-runtime/src/libraries/Native/build-native.sh x64 Debug outconfig net6.0-Haiku-Debug-x64 -os Haiku ninja -cross

That looks like I'm missing something crucial, surely this should be compiling for the target, not the host?

@am11
Copy link
Member

am11 commented Jul 20, 2021

A lot of that patch looks like fixes for building Illumos on Illumos, as most of these are HOST variables.

Yes, haiku would need a "similar" patch, so it gets CMAKE_SYSTEM_NAME=Haiku. Also, when rebuilding after making changes, I delete artifacts directory so cmake runs the configure again.

-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)

e.g. equivalent of

<_MonoBuildEnv Include="PKG_CONFIG_PATH=$(MonoCrossDir)/lib/pkgconfig" />
(path to pkgconfig in sysroot dir) will fix this error.

@jessicah
Copy link
Author

Ah right, I forgot that happens, had been running --clean earlier, whoops, thanks for the reminder :)

@am11
Copy link
Member

am11 commented Jul 20, 2021

Admittedly, Host, Target and Build are three confusing concepts. In MSVC world (coreclr, libraries and corehost), Host in cross compilation is the machine we are executing compiler on and Target is the architecture of target machine. However, in autoconf world, Host is what MSVC refers to as Target and Build is what MSVC refers to as Host. Target in autoconf is a special case, where compiler itself is built on a different architecture than Host and Build and we are pointing to its destination triplet:

In other words, when mono (which was and still is primarily autoconfig-like) is talking about host of cross-compiler, it means target by normal logic. Therefore, I just follow the nearby logic. :)

illumos and FreeBSD are the closest matches to Haiku, as both of them cross compile on amd64 for amd64.

@jessicah
Copy link
Author

Ah okay. Well, it looks like it may have built the cross mono stuff.

Log: https://gist.github.com/jessicah/647f1e8e033c96eb2a47ed3f526e47dd

I guess I can try copying some stuff over to a Haiku install, and seeing what happens.

What will be the next steps, assuming I can get something to run on Haiku?

@jessicah
Copy link
Author

Okay, copied artifacts to my Haiku, and the mono-sgen binaries under artifacts/obj/mono/Haiku.x64.Debug run :)

@am11
Copy link
Member

am11 commented Jul 20, 2021

That was fast. Great progress! It took me way longer to get this far. 🤣

On Linux box, where you have cross compiled, you can run:

# if pwd is your dotnet-runtime directory
cd ..
dotnet-runtime/.dotnet new console -n helloworldapp
cd hellowwoldapp
../dotnet-runtime/.dotnet publish -c Release -o mypublishdir

then edit: mypublishdir/helloworldapp.runtimeconfig.json and change version line to "version": "6.0.0-dev".

Copy mypublishdir to Haiku system and run mono-sgen mypublishdir/helloworldapp.dll.

It may emit a huge diagnostics and fail, but that's not the product we are interested in. We want dotnet(1) to work. :)


A few notes about the setup:

  • if we extract function(locate_toolchain_exec exec var) out of this if/elseif block:
    to share and use the same pattern for Haiku, that will make it selfcontained in a way that compiler detection would look something like:
    -- Check for working C compiler: /runtime/.tools/x64/bin/x86_64-haiku-gcc -- works
    instead of:
    -- Check for working C compiler: /usr/bin/clang-10 -- works
    the benefit of using toolchain from the sysroot is that cmake will be using all tools (linker, loader, objcopy etc.) from same original toolchain, rather than mix and match, which usually is best to avoid.
  • that will likely fix the ICU hack as well as krb5 lookup issue.

Next step would be to port src/native/corehost, i.e. ./build.sh -s host+packs -os haiku -cross -c Release which produces package tarballs under /artifacts/packages. I have only tried it with clr+mono+libs+host+packs, but not just mono+libs+host+packs alone.

The method I followed to test mono on amd64 was to copy artifacts/packages/Release/Shipping/dotnet-runtime-6.0.0-dev-illumos-x64.tar.gz tarball file and artifacts/bin/mono/illumos.x64.Release/ directory on OpenIndiana machine, extract .tar in ~/.dotnet directory and then overwrite libcoreclr.so and System.Private.CoreLib.dll from mono to ~/.dotnet/shared/Microsoft.NETCore.App/6.0.0-dev/libcoreclr.so and .dotnet/shared/Microsoft.NETCore.App/6.0.0-dev/System.Private.CoreLib.dll respectively, and then ran the published application with ~/.dotnet/dotnet helloworld.dll.

@jessicah
Copy link
Author

Hmm, running mono-sgen gives:

* Assertion at /home/jessi/source/dotnet-runtime/src/mono/mono/metadata/assembly.c:3087, condition 'corlib' not met

Seems like it doesn't know where to look for the dlls. Tried setting MONO_PATH to various values, but no dice.

I'll look into using the location_toolchain_exec next, might help avoid installing symlinks in /usr/bin, since clang doesn't really know to look in non-standard locations with the current compile switches.

@jessicah
Copy link
Author

Well, making heaps more progress on coreclr/corehost, but now the c++ compiler has decided it doesn't know what size_t is. My CMake craft isn't that good, so if you have any ideas, would be great :)

Log: https://gist.github.com/jessicah/b7f48ab99909f4aaf2a8e11579a5c3b3

@am11
Copy link
Member

am11 commented Jul 21, 2021

Error is coming from system header. Looks like string.h is missing or some macro definition in cmake which controls including string.h in system headers.

I tried build-rootfs from haiku branch, but it is failing with:

Chmod1 bin.linuxx86/jam 
...updated 33 target(s)...
Building cross tools with 2 parallel jobs
Invalid argument: `--sysroot'

does haiku/configure require some patch to support --sysroot option?

@janvorli
Copy link
Member

@waddlesplash you can disable the W^X by default on Haiku, actually, we do that for Rosetta x64 too - I've incorrectly stated above that we use double mapping even with Rosetta. For Rosetta, it didn't work properly as once rosetta jitted a block of code, it wasn't able to see that the code has changed via the other mapping, so any modifications to code pages that were already jitted by rosetta were never executed.
You can also disable it by setting the DOTNET_EnableWriteXorExecute to 0.

@trungnt2910
Copy link
Contributor

Haiku now supports creating shm files on memory as well as mapping them, so why should we disable this?

The real problem here is that Haiku does not provide a way to cleanly reserve and commit memory in a way similar to the Win32 API. Various features of the CoreCLR (not just the doublemapper, but also GC among other things) tries to map a huge memory block and then commit it bit by bit using mprotect.

On Haiku to be able to map these huge blocks at all, either MAP_NORESERVE need to be passed to request an overcommitting region or a private API that does not map memory but only reserves addresses (reserve_address_range) has to be used instead.

But after that there is no way to cleanly commit the memory areas (clear the overcommit flag or map the memory in the reserved area). A mmap with MAP_FIXED would be a tempting solution, but that destroys any existing pages in the requested range, while CoreCLR seems to rely on the Windows behavior of MEM_COMMIT ignoring existing pages.

@trungnt2910
Copy link
Contributor

The requested assembly still run properly, but until cleanup it fails because of something that looks like a double free.

In the end it was indeed a double free, but it was not the code that I initially pointed. The usage of a lot of inline functions and macros made debugging a lot more complicated.

This is not Haiku-specific and can possibly be triggered on any platform with a stack size small enough, so I have opened a separate pull request.

@trungnt2910
Copy link
Contributor

Got this very weird exception message whenever I try to obtain Exception.StackTrace but only in Release builds:

Array of type 'Entry[System.__Canon,System.Resources.ResourceLocator]' from assembly 'System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' cannot be created because base value type is too large.

Exception.Message and other members that are not related to StackTrace works fine. Throwing and catching an exception works fine.

@trungnt2910
Copy link
Contributor

trungnt2910 commented May 18, 2023

Latest weird error, this time encountered when running dotnet --version.

/Data/dotnet> dotnet --version

Assert failure(PID 2661 [0x00000a65], Thread: 2661 [0x0a65]): heap_segment_committed (region) == heap_segment_mem (region)
    File: /home/trung/dotnet-runtime/src/coreclr/gc/gc.cpp Line: 41544
    Image: /Data/dotnet/dotnet

Abort
Kill Thread

@trungnt2910
Copy link
Contributor

Previous issue resolved, some bug related to Haiku memory allocation is to blame.

Now, I am running into this with dotnet --help:

image

It seems like .NET uses epoll/kqueue to handle IO, but Haiku does not provide such an API yet. Is there a way to emulate this using poll in .NET's codebase?

@danmoseley
Copy link
Member

Created a label, but only this issue needs it right now 😄

@trungnt2910
Copy link
Contributor

From #90695:

Since the full RID graph isn't supposed to be updated any more

Does this mean that something happened in .NET 8 that disallows any further RID addition? Can Haiku not get its own RID?

@am11
Copy link
Member

am11 commented Aug 19, 2023

Yup, dotnet/designs#260. Now the target RID is added in corehost artifacts at the build-time.

@trungnt2910
Copy link
Contributor

Now the target RID is added in corehost artifacts at the build-time.

Can you please point out where in the codebase this is done?

@trungnt2910
Copy link
Contributor

Yup, dotnet/designs#260.

From what I understand from that issue and related materials:

  • dotnet does not wish to continue maintaining volatile a list of runtimes and versions.
  • It instead wants to push this responsibility down to library maintainers.
  • Therefore, the usage of the RID graph in runtime.json and related files is deprecated and will be removed in a future version of .NET. The preferred way is through some per-project MSBuild configuration. If runtime.json continues to be used, a PortableRuntimeIdentifierGraph.json distributed with the SDK will be used instead. This JSON file is not different from that found in the runtime repo, except that all information related to Linux distros and OS versions are removed.
  • The change focuses on Linux distros and its different versions. OSes that have only one consistent distribution like OSX and Windows is not discussed in any of the issues I have read.

So, what will happen to non-Linux UNIXes like FreeBSD and illumos? What will happen to Haiku, which is a unique OS different from the average UNIX as much as FreeBSD is different from Linux?

Since PortableRuntimeIdentifierGraph.json is distributed with the SDK, is a Haiku-aware SDK required to build a version of .NET that supports Haiku, even when cross-compiling from Linux?

@am11
Copy link
Member

am11 commented Aug 20, 2023

Can you please point out where in the codebase this is done?

#84100

So, what will happen to non-Linux UNIXes like FreeBSD and illumos? What will happen to Haiku, which is a unique OS different from the average UNIX as much as FreeBSD is different from Linux?

corehost will get haiku-x64 at build time, and runtime doesn't need to know about more details, such as, versions or distros. If someone has a special use-case and they want the host to probe the legacy, now-frozen, runtime ID graph, they can opt-in the legacy mode with <UseRidGraph>true</UseRidGraph> in their project. Since Haiku is not supported pre- .NET 8, we can make SDK error out if someone sets <UseRidGraph>true</UseRidGraph> along with <RuntimeIdentifier>haiku-x64</RuntimeIdentifier> in their project file.

Since PortableRuntimeIdentifierGraph.json is distributed with the SDK, is a Haiku-aware SDK required to build a version of .NET that supports Haiku, even when cross-compiling from Linux?

SDK does not stop us for introducing new platforms in runtime repo. corehost always adds the RID of build-target, so that will continue to work after the recent breaking changes. There is even a CI with banana-x64 RID to test "whatever the platform maybe, everything should work" case.

@trungnt2910
Copy link
Contributor

So, this means that when an SDK runs on a corehost compiled specifically for Haiku, haiku-x64 will get recognized, because that information is baked into the binary during build time.

This would still, however, prevent cross-compilation from an SDK running on a corehost that is not built for Haiku, for example, the one that goes with Linux?

@am11
Copy link
Member

am11 commented Aug 20, 2023

There are two scenarios:

  1. .NET packaging cross-build: cross-build uses target RID in corehost, so when we cross-build for freebsd-x64 or illumos-x64 on linux-x64, that built runtime package, together with SDK package is all we need in the platform port (e.g. FreeBSD ports) and there is no difference had we built dotnet-runtime or SDK on the target platform (-p:CrossBuild=false). In fact, once you will have a few releases of haiku-x64 available, you won't need to cross-build from linux-x64; you can but it would be optional. Right now, when the platform is new and there is no existing dotnet support on Haiku, cross-build is the only choice.

  2. End-users cross-building their .NET app: when end-user is publishing an app for $other platform (e.g. target:win-x64 from linux-x64 or macOS-arm64 etc.), they pass --rid <desired-target-RID> and at that point, the toolchain (idempotently) downloads the "runtime pack" from NuGet and uses it for the desired-target-RID build. Which means, corehost's build platform is irrelevant here. The code which creates the app normally[1] is managed .NET code, which means it is platform-agnostic. It is basically gluing the (pre-built) apphost / singlefilehost / nethost etc., which are coming from runtime pack, with the user code:

    BinaryUtils.WriteToStream(memoryMappedViewAccessor, fileStream, sourceAppHostLength);

You can port .NET runtime and runtime libraries and continue to cross-build runtime packages on linux-x64, without caring about the SDK. Once runtime packages are built, you can then add Haiku platform spec in the dotnet/sdk and dotnet/installer (a few places in the SDK having the platform list, mainly for stuff like validation error messages).

[1] NativeAOT application model is an exception, which requires cross-toolchain (e.g. gcc for target haiku-x64, or clang which is usually cross-target), but not all platforms support NativeAOT yet (it is currently supported by {linux,osx,win}-{x64,arm64} only), so it is an optional component.

@trungnt2910
Copy link
Contributor

Right now, when the platform is new and there is no existing dotnet support on Haiku, cross-build is the only choice.

Is there any hope in https://github.com/dotnet/dotnet? Currently, I know that it only supports Linux and may assume various Linux-specific environment details, but it is said that the support will be extended to OSX and Windows in .NET 9. With a certain level of cross-platformness, should it be easier to port this repo to another platform and build .NET there without relying on an existing .NET environment?

you can then add Haiku platform spec in the dotnet/sdk

I am already doing that
(trungnt2910/dotnet-sdk@79010f6). Right now, the SDK does not seem to support cross-compilation, requiring a few hacks to allow it to resolve the correct OS name and package versions. My unofficial dotnet builds all include a working SDK enough to build many console applications and some simple library projects like GtkSharp.

That said, it is not sufficient to build the whole .NET runtime from source, because it seems to expect more to be available for Haiku:

/boot/home/Desktop/dotnet/sdk/8.0.100-rc.2.23416.2/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(90,5): error NETSDK1212: IsTrimmable is not supported for the target framework. Consider multi-targeting to a supported framework to enable trimming, and set IsTrimmable only for the supported frameworks. For example: [/boot/home/Desktop/work/dotnet-runtime/Build.proj]
/boot/home/Desktop/dotnet/sdk/8.0.100-rc.2.23416.2/Sdks/Microsoft.NET.Sdk/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets(90,5): error NETSDK1212: <IsTrimmable Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0'))">true</IsTrimmable> [/boot/home/Desktop/work/dotnet-runtime/Build.proj]
/boot/home/Desktop/work/dotnet-runtime/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.sfxproj : error NU1102: Unable to find package Microsoft.NETCore.App.Host.linux-x64 with version (= 8.0.0-rc.2.23416.2) [/boot/home/Desktop/work/dotnet-runtime/Build.proj]
/boot/home/Desktop/work/dotnet-runtime/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.sfxproj : error NU1102:   - Found 1405 version(s) in dotnet8 [ Nearest version: 8.0.0-rc.2.23417.4 ] [/boot/home/Desktop/work/dotnet-runtime/Build.proj]
/boot/home/Desktop/work/dotnet-runtime/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.sfxproj : error NU1102:   - Found 132 version(s) in dotnet-public [ Nearest version: 8.0.0-preview.7.23375.6 ] [/boot/home/Desktop/work/dotnet-runtime/Build.proj]
/boot/home/Desktop/work/dotnet-runtime/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.sfxproj : error NU1102:   - Found 1 version(s) in dotnet-eng [ Nearest version: 5.0.0-alpha.1.19618.1 ] [/boot/home/Desktop/work/dotnet-runtime/Build.proj]

[truncated]

@am11
Copy link
Member

am11 commented Aug 20, 2023

Impressive progress, @trungnt2910! In trungnt2910/dotnet-sdk@79010f6, you could also search with git grep -i freebsd to find other/all places in dotnet/sdk which care for platform identification and add the "haiku" entry alongside, then do the same dotnet/installer repo. That might eliminate/reduce those hacks you mentioned.

In general, code-wise, you may want to bring this port to the same plan as FreeBSD and then for the missing infrastructure parts, we can follow the footsteps of @Thefrank et al. dotnet/source-build#1139 (comment). By using the same approach they've used to make dotnet packages available in FreeBSD ports so far, it might help engineering teams to figure out which parts need to provide variation across multiple community-supported platforms (Haiku probably wouldn't need old versions by the time dotnet port is generally available which may make things relatively simpler). VMR (aka dotnet/dotnet) has a future in more platform support, but that will not exempt the initial port steps for new platforms (1. runtime, 2. SDK, 3. installer, 4. diagnostics repos etc.).

@trungnt2910
Copy link
Contributor

In that commit, I have already ported done this and ported the SDK to Haiku.

However, what is dotnet/installer and what does it do? It claims to be the installer for .NET, but for Unix, do the tarballs already suffice?

@am11
Copy link
Member

am11 commented Aug 30, 2023

However, what is dotnet/installer and what does it do? It claims to be the installer for .NET, but for Unix, do the tarballs already suffice?

https://github.com/dotnet/installer#net-sdk-installers

Installer repo creates the final binary tarball for each platform, signs and versions it. This is where the version compatibility between several components (which form the "dotnet" package) is resolved and the EndToEnd tests run. You can think of it as part of SDK, split for engineering reasons (and one day, may merge back to SDK repo).

@trungnt2910
Copy link
Contributor

We use LLVM libunwind on macOS and FreeBSD

I see that there is a src/native/external/llvm-libunwind in .NET's tree, yet FreeBSD still has CLR_CMAKE_USE_SYSTEM_LIBUNWIND for CoreCLR.

Is the in-tree LLVM libunwind restricted to NativeAOT, or is it just that nobody has come to make the change?

@am11
Copy link
Member

am11 commented Sep 6, 2023

We use LLVM libunwind on macOS and FreeBSD

There was a mistake in my comment.

Correction:

  • FreeBSD is using HP libunwind from packages.
  • macOS is using system libunwind (which was open-sourced in 2013 and contributed to LLVM project as libunwind, but mac ships it with operating system possibly with some minor differences)
  • By default, Linux portable builds use in-tree src/native/external/libunwind, and non-portable builds use system libunwind (HP or LLVM depending on the result of these introspection: HAVE_UNW_GET_SAVE_LOC and HAVE_UNW_GET_ACCESSORS 5a2478f). We can use in-tree with non-portable builds and system one with portable builds by overriding the defaults.
  • On NativeAOT, all Unix-y platforms use src/native/external/llvm-libunwind.

Yes, src/native/external/llvm-libunwind is only tested with NativeAOT, and (AFAIK) nobody has tried it with CoreCLR build. We currently have patches which haven't been upstreamed (yet: #72655).

You may try wiring it up using a cmake knob like CLR_USE_IN_TREE_LLVM_LIBUNWIND and set it to ON for Haiku by default.

@trungnt2910
Copy link
Contributor

Latest builds are failing with this error:

  [  7%] Building CXX object inc/CMakeFiles/corguids.dir/__/pal/prebuilt/idl/cordebug_i.cpp.o
  In file included from /home/runner/work/dotnet-builds/dotnet-builds/runtime/src/coreclr/pal/inc/rt/palrt.h:630,
                   from /home/runner/work/dotnet-builds/dotnet-builds/runtime/src/coreclr/pal/inc/rt/rpc.h:15,
                   from /home/runner/work/dotnet-builds/dotnet-builds/runtime/src/coreclr/pal/prebuilt/idl/cordebug_i.cpp:29:
  /home/runner/work/dotnet-builds/dotnet-builds/runtime/src/coreclr/pal/inc/rt/safecrt.h:1093:16: error: conflicting declaration of C function 'size_t wcsnlen(const WCHAR*, size_t)'
   1093 | size_t __cdecl wcsnlen(const WCHAR *inString, size_t inMaxSize);
        |                ^~~~~~~
  In file included from /home/runner/work/dotnet-builds/dotnet-builds/dotnet-rootfs/boot/system/develop/headers/posix/wctype.h:10,
                   from /home/runner/work/dotnet-builds/dotnet-builds/runtime/src/coreclr/pal/inc/pal.h:51,
                   from /home/runner/work/dotnet-builds/dotnet-builds/runtime/src/coreclr/pal/inc/rt/palrt.h:136:
  /home/runner/work/dotnet-builds/dotnet-builds/dotnet-rootfs/boot/system/develop/headers/posix/wchar.h:122:17: note: previous declaration 'size_t wcsnlen(const wchar_t*, size_t)'
    122 | extern size_t   wcsnlen(const wchar_t *wcs, size_t maxLength);
        |                 ^~~~~~~
  /home/runner/work/dotnet-builds/dotnet-builds/runtime/src/coreclr/pal/inc/rt/safecrt.h:1098:16: error: conflicting declaration of C function 'size_t wcsnlen(const WCHAR*, size_t)'
   1098 | size_t __cdecl wcsnlen(const WCHAR *inString, size_t inMaxSize)
        |                ^~~~~~~
  /home/runner/work/dotnet-builds/dotnet-builds/dotnet-rootfs/boot/system/develop/headers/posix/wchar.h:122:17: note: previous declaration 'size_t wcsnlen(const wchar_t*, size_t)'
    122 | extern size_t   wcsnlen(const wchar_t *wcs, size_t maxLength);
        |                 ^~~~~~~
  make[2]: *** [inc/CMakeFiles/corguids.dir/build.make:76: inc/CMakeFiles/corguids.dir/__/pal/prebuilt/idl/cordebug_i.cpp.o] Error 1
  make[1]: *** [CMakeFiles/Makefile2:3250: inc/CMakeFiles/corguids.dir/all] Error 2
  make[1]: *** Waiting for unfinished jobs....

Seems like whoever included wctype.h did not expect wchar.h to be included as well.

According to the POSIX Standard, however:

[CX] [Option Start] Inclusion of the <wctype.h> header may make visible all symbols from the headers <ctype.h>, <stdarg.h>, <stddef.h>, <stdio.h>, <stdlib.h>, <string.h>, <time.h>, and <wchar.h>. [Option End]

@am11
Copy link
Member

am11 commented Apr 30, 2024

wctype.h is mainly used by paltests. Try applying this patch:

diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h
index 70b934a8ccd..6aec0a80063 100644
--- a/src/coreclr/pal/inc/pal.h
+++ b/src/coreclr/pal/inc/pal.h
@@ -48,7 +48,6 @@ Abstract:
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <wctype.h>
 
 #ifdef __cplusplus
 extern "C++"
diff --git a/src/coreclr/pal/inc/pal_mstypes.h b/src/coreclr/pal/inc/pal_mstypes.h
index d59103002d1..102f3fe512f 100644
--- a/src/coreclr/pal/inc/pal_mstypes.h
+++ b/src/coreclr/pal/inc/pal_mstypes.h
@@ -541,6 +541,8 @@ typedef int SSIZE_T;
 static_assert(sizeof(SIZE_T) == sizeof(void*), "SIZE_T should be pointer sized");
 static_assert(sizeof(SSIZE_T) == sizeof(void*), "SSIZE_T should be pointer sized");
 
+char16_t __cdecl PAL_ToLowerInvariant(char16_t);
+
 #ifndef SIZE_T_MAX
 #define SIZE_T_MAX ULONG_PTR_MAX
 #endif // SIZE_T_MAX
diff --git a/src/coreclr/pal/src/cruntime/wchar.cpp b/src/coreclr/pal/src/cruntime/wchar.cpp
index 88340538ebc..9f3175ec96f 100644
--- a/src/coreclr/pal/src/cruntime/wchar.cpp
+++ b/src/coreclr/pal/src/cruntime/wchar.cpp
@@ -24,12 +24,13 @@ Abstract:
 #include "config.h"
 #endif
 
-#include <wctype.h>
 #include <errno.h>
 #include <algorithm>
 
 SET_DEFAULT_DEBUG_CHANNEL(CRT);
 
+#define iswspace(c) (c==0x09 || c==0x0A || c==0x0B || c==0x0C || c==0x0D || c==0x20)
+
 /*--
 Function:
   _wtoi
diff --git a/src/coreclr/pal/src/safecrt/wcslwr_s.cpp b/src/coreclr/pal/src/safecrt/wcslwr_s.cpp
index 184776f21ee..9c04ed66a3c 100644
--- a/src/coreclr/pal/src/safecrt/wcslwr_s.cpp
+++ b/src/coreclr/pal/src/safecrt/wcslwr_s.cpp
@@ -11,7 +11,6 @@
 *
 *******************************************************************************/
 
-#include <wctype.h>
 #include <string.h>
 #include <errno.h>
 #include <limits.h>
@@ -30,7 +29,7 @@ DLLEXPORT errno_t __cdecl _wcslwr_s(char16_t *string, size_t sz)
 
     for (int i = 0; string[i] != 0; i++)
     {
-        string[i] = (char16_t)towlower(string[i]);
+        string[i] = (char16_t)PAL_ToLowerInvariant(string[i]);
     }
 
     _FILL_STRING(string, sz, length + 1);
diff --git a/src/coreclr/pal/tests/palsuite/common/palsuite.h b/src/coreclr/pal/tests/palsuite/common/palsuite.h
index 9494daed71b..d92aa8b8ed0 100644
--- a/src/coreclr/pal/tests/palsuite/common/palsuite.h
+++ b/src/coreclr/pal/tests/palsuite/common/palsuite.h
@@ -26,6 +26,7 @@ typedef unsigned short char16_t;
 #include <minipal/utils.h>
 #include <minipal/types.h>
 #include <errno.h>
+#include <wctype.h>
 
 #define PALTEST(testfunc, testname) \
  int __cdecl testfunc(int argc, char* argv[]); \

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-PAL-coreclr help wanted [up-for-grabs] Good issue for external contributors os-haiku
Projects
No open projects
Development

No branches or pull requests