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

[NativeAOT-LLVM] add support for building WASI and browser debug & release on Linux #2605

Merged
merged 44 commits into from
Aug 23, 2024

Conversation

yowl
Copy link
Contributor

@yowl yowl commented Jun 6, 2024

This PR adds the scripts and YML for building WASI and browser on Linux.

Takes some of the changes from Joel's work at #2614 to build on Linux. I changed some cases of Browser to browser which seemed like the more consistent direction.

Decided to pass TestWrapperTargetsWindows down from runtimelab-post-build-steps.yml to avoid troublesome inferencing.

@jkotas jkotas added the area-NativeAOT-LLVM LLVM generation for Native AOT compilation (including Web Assembly) label Jun 19, 2024
@@ -22,7 +22,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<_SymbolPrefix Condition="'$(_IsApplePlatform)' == 'true'">_</_SymbolPrefix>
<LinkerFlavor Condition="'$(LinkerFlavor)' == '' and '$(_targetOS)' == 'freebsd'">lld</LinkerFlavor>
<LinkerFlavor Condition="'$(LinkerFlavor)' == '' and '$(_linuxLibcFlavor)' == 'bionic'">lld</LinkerFlavor>
<LinkerFlavor Condition="'$(LinkerFlavor)' == '' and '$(_targetOS)' == 'linux'">bfd</LinkerFlavor>
<LinkerFlavor Condition="'$(LinkerFlavor)' == '' and '$(_targetOS)' == 'linux'">lld</LinkerFlavor>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should propagate from the top-level LDFLAGS set by the init-compiler.sh script. Is it getting lost somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume from the fact that changing this line to lld makes no difference, that it is arriving as bfd.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something up with args to init-compiler.sh maybe.

@yowl yowl closed this Jul 19, 2024
@yowl yowl reopened this Jul 19, 2024
@yowl yowl marked this pull request as ready for review July 24, 2024 13:09
@yowl yowl closed this Jul 29, 2024
@yowl yowl reopened this Jul 29, 2024
@yowl yowl closed this Jul 29, 2024
@yowl yowl reopened this Jul 29, 2024
@yowl yowl closed this Jul 29, 2024
@yowl yowl reopened this Jul 29, 2024
@yowl yowl closed this Jul 29, 2024
@yowl yowl reopened this Jul 29, 2024
@yowl yowl closed this Jul 29, 2024
@yowl yowl reopened this Jul 29, 2024
@yowl yowl changed the title [NativeAOT-LLVM] add some steps for wasi linux x64 [NativeAOT-LLVM] add support for building WASI and browser debug & release on Linux Jul 30, 2024
@yowl
Copy link
Contributor Author

yowl commented Jul 30, 2024

cc @dotnet/nativeaot-llvm

Comment on lines 482 to 484
# Browser WebAssembly Linux X64

- ${{ if containsValue(parameters.platforms, 'Browser_wasm_linux_x64') }}:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference would be to name these in a way that makes it clear that they're downstream-specific. E. g. Browser_wasm_linux_x64_naot_llvm; and comment we're adding these because the "stock" wasi-wasm doesn't have the build tools (that sanitizer image) we need.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed

Comment on lines 495 to 500
${{ if eq(parameters.container, '') }}:
container: linux_x64
${{ if ne(parameters.container, '') }}:
container:
image: ${{ parameters.container }}
registry: mcr

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would make sense to hardcode the azurelinux-3.0-cross-amd64-net9.0-sanitizer here instead of runtimelab* YMLs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 118 to 120
#
# Build and test wasi linux with Release libraries and Release runtime with sanitzer container
#

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not fold this into Build and test with Release libraries and Release runtime above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


Write-Host "Invoking CMake configure: 'cmake $CmakeConfigureCommandLine'"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging deleted intentionally?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, thanks


if [ -n "${WASM_HOST_EXECUTABLE}" ]; then
shift
$WASM_HOST_EXECUTABLE "$WASM_BINARY_TO_EXECUTE" $WASM_HOST_ARGS_SEPERATOR "$@"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.cmd also logs the command it is about to run.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added log, thanks.

@@ -1275,8 +1275,12 @@ void DisplayNowayAssertMap()
fout = _wfopen(strJitMeasureNowayAssertFile, W("a"));
if (fout == nullptr)
{
#if !defined(HOST_WINDOWS)
// TODO: how do we print a `const char16_t*` portably?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these changes need for this to compile in CI/locally? There is an upstream change pending that will resolve them; it would be better to omit them here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, locally in docker, so presumably in CI docker as well. Without these changes we cannot compile on the image:

  /runtime/src/coreclr/jit/compiler.cpp:1278:83: error: length modifier 'w' results in undefined behavior or no effect with 's' conversion specifier [-Werror,-Wformat]
   1278 |                 fprintf(jitstdout(), "Failed to open JitMeasureNowayAssertFile \"%ws\"\n",
        |                                                                                  ~^~
  /runtime/src/coreclr/jit/compiler.cpp:1279:25: error: format specifies type 'wchar_t *' but the argument has type 'LPCWSTR' (aka 'const char16_t *') [-Werror,-Wformat]
   1278 |                 fprintf(jitstdout(), "Failed to open JitMeasureNowayAssertFile \"%ws\"\n",
        |                                                                                  ~~~
        |                                                                                  %s
   1279 |                         strJitMeasureNowayAssertFile);
        |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2 errors generated.
  make[3]: *** [jit/CMakeFiles/clrjit_universal_wasm32_x64.dir/build.make:189: jit/CMakeFiles/clrjit_universal_wasm32_x64.dir/compiler.cpp.o] Error 1

@@ -418,6 +418,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<CompileWasmArgs Condition="'$(IlcLlvmExceptionHandlingModel)' == 'cpp'">$(CompileWasmArgs) -mllvm -enable-emscripten-cxx-exceptions</CompileWasmArgs>

<ScriptExt Condition="'$(OS)' == 'Windows_NT'">.bat</ScriptExt>
<ScriptExt Condition="'$(OS)' != 'Windows_NT'"></ScriptExt>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is ScriptExt set by something upstream? If so, this variable should be renamed to something less generic (e. g. _IlcScriptExt, or something like that).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed.

Comment on lines 40 to 43
- Browser_wasm_win
- wasi_wasm_win
- Browser_wasm_linux_x64
- wasi_wasm_linux_x64

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this will not work as-is.

We have two things being published:

  1. Target packages: browser-wasm / wasi-wasm.
    • In the current setup, these are always published and so we'll get package conflicts, since both platforms will be producing the (hopefully) identical target packages.
  2. Host packages.
    • In the current setup, only Browser_wasm_win publishes host packages.

To fix this up, we'll need to adjust the conditions that prevent package conflicts (e. g. only build target packages on Windows, only build host packages on Browser platforms). But I would suggest leaving the official build for a follow-up change.

Suggested change
- Browser_wasm_win
- wasi_wasm_win
- Browser_wasm_linux_x64
- wasi_wasm_linux_x64
- Browser_wasm_win
- wasi_wasm_win

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, reverted

Comment on lines 21 to 23
- script: $(Build.SourcesDirectory)/build$(scriptExt) clr.wasmjit+clr.aot -c $(buildConfigUpper) $(_officialBuildParameter) -ci -cross
env:
ROOTFS_DIR: /crossrootfs/x64

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if you switch the container in the platform definition to linux_x64_sanitizer, this explicit ROOTFS_DIR can be dropped.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that works, thanks

- ${{ elseif eq(parameters.platform, 'wasi_wasm_linux_x64') }}:
- script: |
source $(Build.SourcesDirectory)/wasm-tools/emsdk/emsdk_env.sh
LD_LIBRARY_PATH=/usr/local/lib:/opt/lib:/lib:/usr/lib:/crossrootfs/x64/lib/x86_64-linux-gnu/ $(Build.SourcesDirectory)/src/tests/build$(scriptExt) nativeaot $(buildConfigUpper) -arch:${{ parameters.archType }} -target-os:wasi tree nativeaot /p:LibrariesConfiguration=${{ parameters.librariesConfiguration }}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is a LD_LIBRARY_PATH like this needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because libtinfo.so.5 is only in the rootfs. The host has libtinfo.so.6

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we build the LLVM with libtinfo dependency ourselves or is that for pre-built LLVM?

If we build it ourselves, we can get rid of libtinfo dependency like this: https://github.com/dotnet/runtimelab/pull/741/files#diff-8bb555c9ef0d91e66546d2fa904a310f4d22f129e191dff6b12e4fbdfe65e321R33

@yowl yowl closed this Aug 20, 2024
@yowl
Copy link
Contributor Author

yowl commented Aug 20, 2024

nuget error

@yowl yowl reopened this Aug 20, 2024
@yowl
Copy link
Contributor Author

yowl commented Aug 20, 2024

Green, think I've got all the feedback addressed.

@@ -35,6 +35,7 @@ extends:
parameters:
jobTemplate: /eng/pipelines/common/global-build-job.yml
buildConfig: Release
container: azurelinux-3.0-cross-amd64-net9.0-sanitizer

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
container: azurelinux-3.0-cross-amd64-net9.0-sanitizer

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -3,7 +3,7 @@ cd /D "%1"

echo Installing Wasi SDK

powershell -NoProfile -NoLogo -ExecutionPolicy ByPass -File "%~dp0install-wasi-sdk.ps1"
powershell -NoProfile -NoLogo -ExecutionPolicy ByPass -File "%~dp0install-wasi-sdk.ps1" -InstallDir .

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now unused and can be deleted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right

@@ -0,0 +1,34 @@
[CmdletBinding(PositionalBinding=$false)]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now unused and can be deleted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deleted

@@ -30,12 +30,22 @@ steps:
- ${{ if eq(parameters.platform, 'browser_wasm_win') }}:
- script: |
call $(Build.SourcesDirectory)\wasm-tools\emsdk\emsdk_env
$(Build.SourcesDirectory)/src/tests/build$(scriptExt) nativeaot $(buildConfigUpper) ${{ parameters.archType }} tree nativeaot /p:LibrariesConfiguration=${{ parameters.librariesConfiguration }}
$(Build.SourcesDirectory)/src/tests/build$(scriptExt) nativeaot $(buildConfigUpper) ${{ parameters.archType }} tree nativeaot /p:LibrariesConfiguration=${{ parameters.librariesConfiguration }} /p:TestWrapperTargetsWindows=true

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is concerning that /p:TestWrapperTargetsWindows=true is needed to make things work on Windows. Does that mean the local test build is broken?

Comment on lines 64 to 67
- ${{ elseif in(parameters.platform, 'wasi_wasm_linux_x64_naot_llvm') }}:
- script: |
$(Build.SourcesDirectory)/src/tests/run$(scriptExt) --runnativeaottests ${{ parameters.archType }} $(buildConfigUpper) wasi
displayName: Run WebAssembly tests in single file mode

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does need to be separate? AFAICT it is just the same as the ${{ else }}: below, just different parameter order.

Comment on lines 83 to 85
source $(Build.SourcesDirectory)/wasm-tools/emsdk/emsdk_env.sh
$(Build.SourcesDirectory)/build$(scriptExt) libs.tests -test -a ${{ parameters.archType }} -os ${{ parameters.osGroup }} -lc ${{ parameters.librariesConfiguration }} -rc $(buildConfigUpper) /p:TestNativeAot=true /p:RunSmokeTestsOnly=true
displayName: Build and run WebAssembly libraries tests

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this need to be separate? emsdk_env.sh is already part of build.sh.

Comment on lines 181 to 182
<TestWrapperTargetsWindows>false</TestWrapperTargetsWindows>
<TestWrapperTargetsWindows Condition=" ('$(TargetsWindows)' != '' And '$(TargetsWindows)' ) OR ('$(TargetOS)' == 'android' And '$(TargetArchitecture)' == 'arm64' ) OR ($(WindowsHost) And '$(TargetArchitecture)' == 'wasm')">true</TestWrapperTargetsWindows>
<TestWrapperTargetsWindows Condition="'$(TestWrapperTargetsWindows)' == ''">false</TestWrapperTargetsWindows>
<TestWrapperTargetsWindows Condition=" ('$(TargetsWindows)' != '' And '$(TargetsWindows)' ) OR ('$(TargetOS)' == 'android' And '$(TargetArchitecture)' == 'arm64' )">true</TestWrapperTargetsWindows>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not clear to me any changes to TestWrapperTargetsWindows logic are required.

Here's how the upstream condition will evaluate on Windows-targeting-WASM:

  • ('$(TargetsWindows)' != '' And '$(TargetsWindows)' ) OR ('$(TargetOS)' == 'android' And '$(TargetArchitecture)' == 'arm64' ) OR ($(WindowsHost) And '$(TargetArchitecture)' == 'wasm') => true due to (($(WindowsHost) And '$(TargetArchitecture)' == 'wasm').
    On Not-Windows-targeting-WASM:
  • => "" (none of the Windows conditions are true).

Which is how it is supposed to be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, it's not required. Thanks.

@@ -318,6 +320,30 @@ handle_arguments_local() {
fi
;;

target-os*|-target-os*)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to structure this the same as the Windows and run.sh script: Add wasi/browser arguments (possibly also wasm, though it's not strictly required). It would make the command lines more consistent and simplify CI.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, done.

src/tests/Common/scripts/nativeaottest.sh Outdated Show resolved Hide resolved
@yowl yowl closed this Aug 22, 2024
@yowl yowl reopened this Aug 22, 2024
@yowl yowl closed this Aug 23, 2024
@yowl yowl reopened this Aug 23, 2024
@yowl
Copy link
Contributor Author

yowl commented Aug 23, 2024

A problem with our timers perhaps

Copy link

@SingleAccretion SingleAccretion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM modulo feedback.

Thank you 🚀!

Comment on lines +13 to +14
// TODO-LLVM: This is not upstreamable and should be deleted when https://github.com/dotnet/runtimelab/pull/2614 is merged
#if TARGET_WASI && !NATIVE_AOT

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you open an issue about reverting these changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, #2666

src/tests/build.proj Outdated Show resolved Hide resolved
src/tests/build.sh Outdated Show resolved Hide resolved
@@ -341,7 +341,7 @@ fi
<WatcherRunFile>"$CORE_ROOT/watchdog" $_WatcherTimeoutMins</WatcherRunFile>

<!-- Note that this overwrites CLRTestBashPreCommands rather than adding to it. -->
<CLRTestBashPreCommands Condition="'$(CLRTestKind)' == 'BuildAndRun' and '$(TargetArchitecture)' == 'wasm'"><![CDATA[
<CLRTestBashPreCommands Condition="'$(CLRTestKind)' == 'BuildAndRun' and '$(TargetArchitecture)' == 'wasm' And '$(TargetOS)' == 'browser' And '$(RuntimeFlavor)' == 'mono'"><![CDATA[

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the '$(TargetOS)' == 'browser' check necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, removed.

@yowl
Copy link
Contributor Author

yowl commented Aug 23, 2024

Thanks for the reviews!

@jkotas
Copy link
Member

jkotas commented Aug 23, 2024

Great work! Thanks a lot

@jkotas jkotas merged commit c213405 into dotnet:feature/NativeAOT-LLVM Aug 23, 2024
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-NativeAOT-LLVM LLVM generation for Native AOT compilation (including Web Assembly)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants