Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,27 @@ The .NET Foundation licenses this file to you under the MIT license.
***********************************************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Part of workaround for lack of secondary build artifact import - https://github.com/Microsoft/msbuild/issues/2807 -->
<!-- required Target, but nothing to do for Wasm -->
<Target Name="SetupOSSpecificProps" />

<ItemGroup>
<DirectPInvoke Include="libSystem.Globalization.Native" />
<DirectPInvoke Include="libSystem.Native" />
</ItemGroup>

<Target Name="ValidateEmsdk"
<Target Name="_InitializeEmsdk"
Condition="'$(_targetOS)' == 'browser'">
<!-- $(EMSDK) is typically set by the user and points to a standard emscripten layout. -->
<!-- $(EmscriptenSdkToolsPath) comes from upstream mono workload and points to the dotnet/emsdk-style SDK layout. -->
<!-- See https://github.com/dotnet/runtime/blob/main/src/mono/browser/build/EmSdkRepo.Defaults.props. -->
<Error Text="Emscripten not found, not compiling to WebAssembly. To enable WebAssembly compilation, install Emscripten and ensure the EMSDK environment variable points to the directory containing emsdk.bat"
Condition="'$(EMSDK)' == '' and '$(EmscriptenSdkToolsPath)' == ''" />

<PropertyGroup>
<_NativeWasmSdkBinPath Condition="'$(EMSDK)' != ''">$([MSBuild]::NormalizeDirectory('$(EMSDK)', 'upstream', 'bin'))</_NativeWasmSdkBinPath>
<_NativeWasmSdkBinPath Condition="'$(EMSDK)' == ''">$([MSBuild]::NormalizeDirectory('$(EmscriptenSdkToolsPath)', 'bin'))</_NativeWasmSdkBinPath>
<_EmscriptenScriptsPath Condition="'$(EMSDK)' != ''">$([MSBuild]::NormalizeDirectory('$(EMSDK)', 'upstream', 'emscripten'))</_EmscriptenScriptsPath>
<_EmscriptenScriptsPath Condition="'$(EMSDK)' == ''">$([MSBuild]::NormalizeDirectory('$(EmscriptenSdkToolsPath)', 'emscripten'))</_EmscriptenScriptsPath>
<_EmccScriptExt Condition="$([System.OperatingSystem]::IsWindows())">.bat</_EmccScriptExt>

<CppCompiler Condition="'$(CppCompiler)' == ''">&quot;$(_NativeWasmSdkBinPath)clang&quot;</CppCompiler>
<CppLinker Condition="'$(CppLinker)' == ''">&quot;$(_EmscriptenScriptsPath)emcc$(_EmccScriptExt)&quot;</CppLinker>
</PropertyGroup>
</Target>

<Target Name="ValidateWasiSdk"
<Target Name="_InitializeWasiSdk"
Condition="'$(_targetOS)' == 'wasi'">
<Error Text="Wasi SDK not found, not compiling to WebAssembly. To enable WebAssembly compilation, install Wasi SDK and ensure the WASI_SDK_PATH environment variable points to the directory containing share/wasi-sysroot"
Condition="'$(WASI_SDK_PATH)' == ''" />
Expand All @@ -45,6 +47,26 @@ The .NET Foundation licenses this file to you under the MIT license.

<Warning Text="Wasi SDK version $(_ActualWasiSdkVersion) is being used. This differs from the expected $(_ExpectedWasiSdkVersions) and might result in build or runtime failures."
Condition="!$(_ExpectedWasiSdkVersions.Contains($(_ActualWasiSdkVersion)))" />

<PropertyGroup>
<_NativeWasmSdkBinPath>$([MSBuild]::NormalizeDirectory('$(WASI_SDK_PATH)', 'bin'))</_NativeWasmSdkBinPath>

<CppCompiler Condition="'$(CppCompiler)' == ''">&quot;$(_NativeWasmSdkBinPath)clang&quot;</CppCompiler>
<CppLinker Condition="'$(CppLinker)' == ''">$(CppCompiler)</CppLinker>
</PropertyGroup>
</Target>

<!-- Part of workaround for lack of secondary build artifact import - https://github.com/Microsoft/msbuild/issues/2807 -->
<Target Name="SetupOSSpecificProps" DependsOnTargets="_InitializeEmsdk;_InitializeWasiSdk">
<PropertyGroup>
<_HostToolExeExt Condition="$([System.OperatingSystem]::IsWindows())">.exe</_HostToolExeExt>
<CppLibCreator Condition="'$(CppLibCreator)' == ''">$(_NativeWasmSdkBinPath)llvm-ar$(_HostToolExeExt)</CppLibCreator>
</PropertyGroup>

<ItemGroup>
<DirectPInvoke Include="libSystem.Globalization.Native" />
<DirectPInvoke Include="libSystem.Native" />
</ItemGroup>
</Target>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ The .NET Foundation licenses this file to you under the MIT license.
<NativeBinaryExt Condition="'$(IsNativeExecutable)' != 'true' and '$(_targetOS)' != 'win' and '$(_IsApplePlatform)' != 'true' and '$(NativeLib)' == 'Shared'">.so</NativeBinaryExt>
<NativeBinaryExt Condition="'$(IsNativeExecutable)' != 'true' and '$(_targetOS)' == 'win' and '$(NativeLib)' == 'Static'">.lib</NativeBinaryExt>
<NativeBinaryExt Condition="'$(IsNativeExecutable)' != 'true' and '$(_targetOS)' != 'win' and '$(NativeLib)' == 'Static'">.a</NativeBinaryExt>
<NativeBinaryExt Condition="'$(_targetOS)' == 'browser'">.html</NativeBinaryExt>
<NativeBinaryExt Condition="'$(_targetOS)' == 'browser' and '$(NativeLib)' == 'Shared'">.js</NativeBinaryExt>
<NativeBinaryExt Condition="'$(_targetOS)' == 'wasi'">.wasm</NativeBinaryExt>
<NativeBinaryExt Condition="'$(IsNativeExecutable)' == 'true' and '$(_targetOS)' == 'browser'">.html</NativeBinaryExt>
<NativeBinaryExt Condition="'$(IsNativeExecutable)' != 'true' and '$(_targetOS)' == 'browser' and '$(NativeLib)' == 'Shared'">.js</NativeBinaryExt>
<NativeBinaryExt Condition="'$(_targetOS)' == 'wasi' and '$(NativeLib)' != 'Static'">.wasm</NativeBinaryExt>

<NativeSymbolExt Condition="'$(NativeSymbolExt)' == '' and '$(_IsApplePlatform)' == 'true'">.dSYM</NativeSymbolExt>
<NativeSymbolExt Condition="'$(NativeSymbolExt)' == '' and '$(_targetOS)' == 'win'">.pdb</NativeSymbolExt>
Expand Down Expand Up @@ -408,7 +408,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<Target Name="CompileWasmObjects"
Inputs="@(LlvmObjects)"
Outputs="@(LlvmObjects->'%(NativeObject)')"
DependsOnTargets="InitializeTheListOfLlvmObjects;ValidateEmsdk;ValidateWasiSdk"
DependsOnTargets="InitializeTheListOfLlvmObjects"
Condition="'$(NativeCodeGen)' == 'llvm'">

<MakeDir Directories="$([System.IO.Path]::GetDirectoryName($(NativeBinary)))" />
Expand All @@ -424,25 +424,13 @@ The .NET Foundation licenses this file to you under the MIT license.

<PropertyGroup Condition="'$(_targetOS)' == 'browser'">
<CompileWasmArgs Condition="'$(IlcLlvmExceptionHandlingModel)' == 'cpp'">$(CompileWasmArgs) -mllvm -enable-emscripten-cxx-exceptions</CompileWasmArgs>

<EmccScriptExt Condition="'$(OS)' == 'Windows_NT'">.bat</EmccScriptExt>
<EmccScriptExt Condition="'$(OS)' != 'Windows_NT'"></EmccScriptExt>
<WasmCompilerPath Condition="'$(EMSDK)' != ''">&quot;$(EMSDK)/upstream/bin/clang++&quot;</WasmCompilerPath>
<WasmCompilerPath Condition="'$(EMSDK)' == ''">&quot;$(EmscriptenSdkToolsPath)bin/clang++&quot;</WasmCompilerPath>
<WasmLinkerPath Condition="'$(EMSDK)' != ''">&quot;$(EMSDK)/upstream/emscripten/emcc$(EmccScriptExt)&quot;</WasmLinkerPath>
<WasmLinkerPath Condition="'$(EMSDK)' == ''">&quot;$(EmscriptenSdkToolsPath)emscripten/emcc$(EmccScriptExt)&quot;</WasmLinkerPath>
</PropertyGroup>

<PropertyGroup Condition="'$(_targetOS)' == 'wasi'">
<WasmCompilerPath>&quot;$(WASI_SDK_PATH)/bin/clang++&quot;</WasmCompilerPath>
<WasmLinkerPath>&quot;$(WASI_SDK_PATH)/bin/clang&quot;</WasmLinkerPath>
</PropertyGroup>

<!-- Invoke the compilers in parallel. -->
<ItemGroup>
<ExecProjects Include="$(MSBuildProjectFullPath)">
<AdditionalProperties>
ExecCommand=$(WasmCompilerPath) &quot;%(LlvmObjects.Identity)&quot; -o &quot;%(LlvmObjects.NativeObject)&quot; $(CompileWasmArgs)
ExecCommand=$(CppCompiler) &quot;%(LlvmObjects.Identity)&quot; -o &quot;%(LlvmObjects.NativeObject)&quot; $(CompileWasmArgs)
</AdditionalProperties>
</ExecProjects>
</ItemGroup>
Expand Down Expand Up @@ -621,8 +609,16 @@ The .NET Foundation licenses this file to you under the MIT license.
<CustomLinkerArg Include="@(LinkerArg)" />
</ItemGroup>

<WriteLinesToFile File="$(NativeIntermediateOutputPath)link.rsp" Lines="@(CustomLinkerArg)" Overwrite="true" Encoding="utf-8" />
<Exec Command="$(WasmLinkerPath) @$(NativeIntermediateOutputPath)link.rsp $(EmccExtraArgs)" EnvironmentVariables="@(EmscriptenEnvVars)" />
<WriteLinesToFile File="$(NativeIntermediateOutputPath)link.rsp" Lines="@(CustomLinkerArg)" Overwrite="true" Encoding="utf-8" Condition="'$(NativeLib)' != 'Static'" />
<Exec Command="$(CppLinker) @$(NativeIntermediateOutputPath)link.rsp $(EmccExtraArgs)" EnvironmentVariables="@(EmscriptenEnvVars)" Condition="'$(NativeLib)' != 'Static'" />

<ItemGroup Condition="'$(NativeLib)' == 'Static'">
<CustomLibArg Include="-crs &quot;$(NativeBinary)&quot;" />
<CustomLibArg Include="@(NativeObjects->'&quot;%(Identity)&quot;')" />
</ItemGroup>

<WriteLinesToFile File="$(NativeIntermediateOutputPath)lib.rsp" Lines="@(CustomLibArg)" Overwrite="true" Encoding="utf-8" Condition="'$(NativeLib)' == 'Static'" />
<Exec Command="&quot;$(CppLibCreator)&quot; @$(NativeIntermediateOutputPath)lib.rsp" Condition="'$(NativeLib)' == 'Static'" />

<RelocateMstat Condition="'$(IlcGenerateMstatFile)' == 'true'"
MstatFilePath="$(NativeIntermediateOutputPath)%(ManagedBinary.Filename).mstat"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)..'))" />

<PropertyGroup>
<CLRTestTargetUnsupported Condition="'$(TargetsWasm)' != 'true'">true</CLRTestTargetUnsupported>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<CLRTestKind>BuildAndRun</CLRTestKind>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>

<!-- Test that the C++-based exception dispatch is working. -->
<WasmEnableExceptionHandling>false</WasmEnableExceptionHandling>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<!-- This is the part of the package testing exposed to the runtime test infrastructure.
The projects themselves are intentionally isolated from the rest of the tree. -->
<CLRTestKind>BuildOnly</CLRTestKind>
<CLRTestTargetUnsupported Condition="'$(TargetsWasm)' != 'true'">true</CLRTestTargetUnsupported>
</PropertyGroup>

<Target Name="PublishPackagingTestProject" BeforeTargets="BeforeBuild">
Expand Down
101 changes: 101 additions & 0 deletions src/tests/nativeaot/SmokeTests/HelloWasm/WasmStaticLib.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

public class StaticLibrary
{
static int s_primitiveInt = 10;

[UnmanagedCallersOnly(EntryPoint = "ReturnsPrimitiveInt")]
public static int ReturnsPrimitiveInt()
{
return s_primitiveInt;
}

[UnmanagedCallersOnly(EntryPoint = "ReturnsPrimitiveBool")]
public static bool ReturnsPrimitiveBool()
{
return true;
}

[UnmanagedCallersOnly(EntryPoint = "ReturnsPrimitiveChar")]
public static char ReturnsPrimitiveChar()
{
return 'a';
}

[UnmanagedCallersOnly(EntryPoint = "EnsureManagedClassLoaders")]
public static void EnsureManagedClassLoaders()
{
Random random = new Random();
random.Next();
}

[UnmanagedCallersOnly(EntryPoint = "CheckSimpleExceptionHandling")]
public static int CheckSimpleExceptionHandling()
{
int result = 10;

try
{
Console.WriteLine("Throwing exception");
throw new Exception();
}
catch when (result == 10)
{
result += 20;
}
finally
{
result += 70;
}

return result;
}

private static bool s_collected;

class ClassWithFinalizer
{
~ClassWithFinalizer() { s_collected = true; }
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static void MakeGarbage()
{
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

object[] arr = new object[1024 * 1024];
for (int i = 0; i < arr.Length; i++)
arr[i] = new object();

new ClassWithFinalizer();
}

[UnmanagedCallersOnly(EntryPoint = "CheckSimpleGCCollect")]
public static int CheckSimpleGCCollect()
{
string myString = string.Format("Hello {0}", "world");

MakeGarbage();

Console.WriteLine("Triggering GC");
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

return s_collected ? (myString == "Hello world" ? 100 : 1) : 2;
}
}
34 changes: 34 additions & 0 deletions src/tests/nativeaot/SmokeTests/HelloWasm/WasmStaticLib.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<NativeLib>Static</NativeLib>
<SkipInferOutputType>true</SkipInferOutputType>
<CLRTestKind>BuildAndRun</CLRTestKind>
<CLRTestExitCode>0</CLRTestExitCode>
<RequiresProcessIsolation>true</RequiresProcessIsolation>
<ReferenceXUnitWrapperGenerator>false</ReferenceXUnitWrapperGenerator>

<NativeDriverBinary Condition="'$(TargetsBrowser)' == 'true'">WasmStaticLib.js</NativeDriverBinary>
<NativeDriverBinary Condition="'$(TargetsWasi)' == 'true'">WasmStaticLib.wasm</NativeDriverBinary>
</PropertyGroup>

<ItemGroup>
<Compile Include="WasmStaticLib.cs" />
</ItemGroup>

<Target Name="LinkFinalExecutable" AfterTargets="LinkNative">
<ItemGroup>
<_FinalLinkerArg Include="-o &quot;$(NativeOutputPath)$(NativeDriverBinary)&quot;" />
<_FinalLinkerArg Include="&quot;$(NativeBinary)&quot;" />
<_FinalLinkerArg Include="&quot;$(MSBuildThisFileDirectory)WasmStaticLibDriver.cpp&quot;" />

<!-- This is NOT meant to be a fully robust filter, it's here only to minimize the impact of targets changes. -->
<_ExcludedLinkerArg Include="@(NativeObjects->'&quot;%(Identity)&quot;'->Replace('\', '/'))" />
<_ExcludedLinkerArg Include="-o &quot;$(NativeBinary.Replace('\', '/'))&quot;" />
<_FinalLinkerArg Include="@(CustomLinkerArg)" Exclude="@(_ExcludedLinkerArg)" />
</ItemGroup>

<Exec Command="$(CppLinker) @(_FinalLinkerArg, ' ')" />
</Target>

</Project>
30 changes: 30 additions & 0 deletions src/tests/nativeaot/SmokeTests/HelloWasm/WasmStaticLibDriver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
extern "C" int ReturnsPrimitiveInt();
extern "C" bool ReturnsPrimitiveBool();
extern "C" unsigned short ReturnsPrimitiveChar();
extern "C" void EnsureManagedClassLoaders();
extern "C" int CheckSimpleGCCollect();
extern "C" int CheckSimpleExceptionHandling();

int main()
{
if (ReturnsPrimitiveInt() != 10)
return 1;

if (!ReturnsPrimitiveBool())
return 2;

if (ReturnsPrimitiveChar() != 'a')
return 3;

// As long as no unmanaged exception is thrown
// managed class loaders were initialized successfully
EnsureManagedClassLoaders();

if (CheckSimpleGCCollect() != 100)
return 4;

if (CheckSimpleExceptionHandling() != 100)
return 5;

return 0;
}