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

[release/6.0-preview3] Backport of Add support for using emscripten from packages #50077 #50227

Merged
merged 1 commit into from
Mar 25, 2021
Merged
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
133 changes: 116 additions & 17 deletions src/mono/wasm/build/WasmApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<UsingTask TaskName="WasmLoadAssembliesAndReferences" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
<UsingTask TaskName="PInvokeTableGenerator" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
<UsingTask TaskName="IcallTableGenerator" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
<UsingTask TaskName="Microsoft.WebAssembly.Build.Tasks.RunWithEmSdkEnv" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />

<!--
Required public items/properties:
Expand Down Expand Up @@ -77,8 +76,8 @@

<Target Name="_WasmAotCompileApp" Condition="'$(RunAOTCompilation)' == 'true'">
<Error Condition="'@(_WasmAssembliesInternal)' == ''" Text="Item _WasmAssembliesInternal is empty" />
<Error Condition="'$(EMSDK_PATH)' == ''" Text="%24(EMSDK_PATH) should be set to emscripten sdk" />
<Error Condition="!Exists($(EMSDK_PATH))" Text="Cannot find EMSDK_PATH=$(EMSDK_PATH)" />
<Error Condition="'$(_IsEMSDKMissing)' == 'true'"
Text="$(_EMSDKMissingErrorMessage) Emscripten SDK is required for AOT'ing assemblies." />

<ItemGroup>
<MonoAOTCompilerDefaultAotArguments Include="no-opt" />
Expand Down Expand Up @@ -144,7 +143,7 @@
UseLLVM="true"
DisableParallelAot="true"
DedupAssembly="$(_WasmDedupAssembly)"
LLVMPath="$(EMSDK_PATH)\upstream\bin">
LLVMPath="$(EmSdkUpstreamBinPath)">
<Output TaskParameter="CompiledAssemblies" ItemName="_WasmAssembliesInternal" />
<Output TaskParameter="FileWrites" ItemName="FileWrites" />
</MonoAOTCompiler>
Expand Down Expand Up @@ -194,7 +193,7 @@
</ItemGroup>
</Target>

<Target Name="_BeforeWasmBuildApp" DependsOnTargets="_SetWasmBuildNativeDefaults">
<Target Name="_BeforeWasmBuildApp" DependsOnTargets="_SetupEmscripten;_SetWasmBuildNativeDefaults">
<Error Condition="'$(IntermediateOutputPath)' == ''" Text="%24(IntermediateOutputPath) property needs to be set" />
<Error Condition="!Exists('$(MicrosoftNetCoreAppRuntimePackRidDir)')" Text="MicrosoftNetCoreAppRuntimePackRidDir=$(MicrosoftNetCoreAppRuntimePackRidDir) doesn't exist" />
<Error Condition="@(WasmAssembliesToBundle->Count()) == 0" Text="WasmAssembliesToBundle item is empty. No assemblies to process" />
Expand Down Expand Up @@ -222,17 +221,117 @@
</ItemGroup>
</Target>

<Target Name="_SetWasmBuildNativeDefaults">
<Target Name="_SetupEmscripten">
<!-- If $(Emscripten*ToolsPath) etc propeties are already set (by the workload pack),
then prefer that, and ignore $(EMSDK_PATH) -->

<!-- If $(Emscripten*ToolsPath) etc propeties are *not* set (by the workload pack),
then try to construct the same properties based on $(EMSDK_PATH) -->
<PropertyGroup Condition="'$(EmscriptenSdkToolsPath)' == '' and '$(EMSDK_PATH)' != ''">
<EmscriptenSdkToolsPath>$([MSBuild]::EnsureTrailingSlash($(EMSDK_PATH)))</EmscriptenSdkToolsPath>
<EmSdkUpstreamBinPath>$([MSBuild]::NormalizeDirectory($(EmscriptenSdkToolsPath), 'upstream', 'bin'))</EmSdkUpstreamBinPath>

<_NodeToolsBasePath>$(EmscriptenSdkToolsPath)node</_NodeToolsBasePath>

<!-- gets the path like emsdk/python/3.7.4-2_64bit -->
<_NodeToolsVersionedPath Condition="Exists($(_NodeToolsBasePath))">$([System.IO.Directory]::GetDirectories($(_NodeToolsBasePath)))</_NodeToolsVersionedPath>
<EmscriptenNodeToolsPath Condition="'$(_NodeToolsVersionedPath)' != ''">$(_NodeToolsVersionedPath)</EmscriptenNodeToolsPath>

<_UsingEMSDK_PATH>true</_UsingEMSDK_PATH>
</PropertyGroup>

<PropertyGroup>
<_EMSDKMissingPaths Condition="'$(_EMSDKMissingPaths)' == '' and ('$(EmscriptenSdkToolsPath)' == '' or !Exists('$(EmscriptenSdkToolsPath)'))">%24(EmscriptenSdkToolsPath)=$(EmscriptenSdkToolsPath) </_EMSDKMissingPaths>
<_EMSDKMissingPaths Condition="'$(_EMSDKMissingPaths)' == '' and ('$(EmscriptenNodeToolsPath)' == '' or !Exists('$(EmscriptenNodeToolsPath)'))">%24(EmscriptenNodeToolsPath)=$(EmscriptenNodeToolsPath) </_EMSDKMissingPaths>
<_EMSDKMissingPaths Condition="'$(_EMSDKMissingPaths)' == '' and ('$(EmSdkUpstreamBinPath)' == '' or !Exists('$(EmSdkUpstreamBinPath)'))">%24(EmSdkUpstreamBinPath)=$(EmSdkUpstreamBinPath) </_EMSDKMissingPaths>
</PropertyGroup>

<!-- Emscripten uses system python on Linux, so we don't need $(EmscriptenPythonToolsPath) -->
<PropertyGroup Condition="'$(_UsingEMSDK_PATH)' == 'true' and !$([MSBuild]::IsOSPlatform('linux'))">
<_PythonToolsBasePath>$(EmscriptenSdkToolsPath)python</_PythonToolsBasePath>
<_PythonToolsVersionedPath Condition="Exists($(_PythonToolsBasePath))">$([System.IO.Directory]::GetDirectories($(_PythonToolsBasePath)))</_PythonToolsVersionedPath>
<EmscriptenPythonToolsPath Condition="'$(_PythonToolsVersionedPath)' != ''">$(_PythonToolsVersionedPath)</EmscriptenPythonToolsPath>

<_EMSDKMissingPaths Condition="'$(_EMSDKMissingPaths)' == '' and ('$(EmscriptenPythonToolsPath)' == '' or !Exists('$(EmscriptenPythonToolsPath)'))">%24(EmscriptenPythonToolsPath)=$(EmscriptenPythonToolsPath) </_EMSDKMissingPaths>
</PropertyGroup>

<PropertyGroup>
<_EMSDKMissingErrorMessage Condition="'$(EMSDK_PATH)' == '' and '$(EmscriptenSdkToolsPath)' == ''">Could not find emscripten sdk. Either set %24(EMSDK_PATH), or use workloads to get the sdk.</_EMSDKMissingErrorMessage>

<_EMSDKMissingErrorMessage Condition="'$(_EMSDKMissingErrorMessage)' == '' and '$(_UsingEMSDK_PATH)' != 'true' and '$(_EMSDKMissingPaths)' != ''">Emscripten from the workload is missing some paths: $(_EMSDKMissingPaths).</_EMSDKMissingErrorMessage>
<_EMSDKMissingErrorMessage Condition="'$(_EMSDKMissingErrorMessage)' == '' and '$(_UsingEMSDK_PATH)' == 'true' and !Exists($(EMSDK_PATH))">Could not find Emscripten sdk at %24(EMSDK_PATH)=$(EMSDK_PATH) .</_EMSDKMissingErrorMessage>
<_EMSDKMissingErrorMessage Condition="'$(_EMSDKMissingErrorMessage)' == '' and '$(_UsingEMSDK_PATH)' == 'true' and '$(_EMSDKMissingPaths)' != ''">Specified Emscripten sdk at %24(EMSDK_PATH)=$(EMSDK_PATH) is missing some paths: $(_EMSDKMissingPaths).</_EMSDKMissingErrorMessage>

<_IsEMSDKMissing Condition="'$(_EMSDKMissingErrorMessage)' != ''">true</_IsEMSDKMissing>
</PropertyGroup>

<PropertyGroup>
<_IsEMSDKMissing Condition="'$(EMSDK_PATH)' == '' or !Exists('$(EMSDK_PATH)')">true</_IsEMSDKMissing>
<EmscriptenSdkToolsPath Condition="'$(EmscriptenSdkToolsPath)' != ''" >$([MSBuild]::NormalizeDirectory($(EmscriptenSdkToolsPath)))</EmscriptenSdkToolsPath>
<EmscriptenNodeToolsPath Condition="'$(EmscriptenNodeToolsPath)' != ''" >$([MSBuild]::NormalizeDirectory($(EmscriptenNodeToolsPath)))</EmscriptenNodeToolsPath>
<EmscriptenPythonToolsPath Condition="'$(EmscriptenPythonToolsPath)' != ''">$([MSBuild]::NormalizeDirectory($(EmscriptenPythonToolsPath)))</EmscriptenPythonToolsPath>
<EmSdkUpstreamBinPath Condition="'$(EmSdkUpstreamBinPath)' != ''" >$([MSBuild]::NormalizeDirectory($(EmSdkUpstreamBinPath)))</EmSdkUpstreamBinPath>
</PropertyGroup>

<!-- Environment variables required for running emsdk commands like `emcc` -->
<ItemGroup Condition="'$(EmscriptenSdkToolsPath)' != ''">
<EmscriptenEnvVars Include="DOTNET_EMSCRIPTEN_LLVM_ROOT=$(EmscriptenSdkToolsPath)bin" />
<EmscriptenEnvVars Include="DOTNET_EMSCRIPTEN_BINARYEN_ROOT=$(EmscriptenSdkToolsPath)" />
<EmscriptenEnvVars Include="DOTNET_EMSCRIPTEN_NODE_JS=$([MSBuild]::NormalizePath($(EmscriptenNodeToolsPath), 'bin', 'node$(_ExeExt)'))" />
</ItemGroup>

<!-- Paths to be added to environment variable `PATH` -->
<ItemGroup Condition="'$(EmscriptenSdkToolsPath)' != '' and '$(_UsingEMSDK_PATH)' != 'true'">
<_EmscriptenAddPATH Condition="'$(EmscriptenPythonToolsPath)' != ''" Include="$(EmscriptenPythonToolsPath)bin" />
<_EmscriptenAddPATH Include="$(EmscriptenSdkToolsPath)emscripten" />
</ItemGroup>

<ItemGroup Condition="'$(EmscriptenSdkToolsPath)' != '' and '$(_UsingEMSDK_PATH)' == 'true'">
<_EmscriptenAddPATH Include="$(EmscriptenSdkToolsPath)" />
<_EmscriptenAddPATH Include="$(EmscriptenNodeToolsPath)bin" />
<_EmscriptenAddPATH Include="$([MSBuild]::NormalizeDirectory($(EmscriptenSdkToolsPath), 'upstream', 'emscripten'))" />
</ItemGroup>

<!-- paths with trailing slash, like:
c:\foo\bar\

.. will become PATH=c:\foo\bar\;c:\xyz

.. which would escape the semicolon path separator. So, change
that to c:\foo\bar\. so the setting will become:

PATH=c:\foo\bar\.;c:\xyz
-->
<ItemGroup>
<_EmscriptenAddPATHFixed Include="%(_EmscriptenAddPATH.Identity)."
Condition="$([MSBuild]::ValueOrDefault('%(_EmscriptenAddPATH.Identity)', '').EndsWith('\'))" />
<_EmscriptenAddPATHFixed Include="@(_EmscriptenAddPATH)"
Condition="!$([MSBuild]::ValueOrDefault('%(_EmscriptenAddPATH.Identity)', '').EndsWith('\'))" />
<_EmscriptenAddPATH Remove="@(_EmscriptenAddPATH)" />
<_EmscriptenAddPATH Include="@(_EmscriptenAddPATHFixed)" />
</ItemGroup>

<PropertyGroup>
<_EmscriptenAddPATHProperty Condition="'$(OS)' == 'Windows_NT'">@(_EmscriptenAddPATH -> '%(Identity)', '%3B')</_EmscriptenAddPATHProperty>
<_EmscriptenAddPATHProperty Condition="'$(OS)' != 'Windows_NT'">@(_EmscriptenAddPATH -> '%(Identity)', ':')</_EmscriptenAddPATHProperty>
</PropertyGroup>

<ItemGroup>
<!-- semicolon is a msbuild property separator. It is also the path separator on windows.
So, we need to escape it here, so the paths don't get split up when converting
to string[] for passing to Exec task -->
<EmscriptenEnvVars Include="PATH=$(_EmscriptenAddPATHProperty)%3B$([MSBuild]::Escape($(PATH)))" Condition="'$(OS)' == 'Windows_NT'" />

<EmscriptenEnvVars Include="PATH=$(_EmscriptenAddPATHProperty):$(PATH)" Condition="'$(OS)' != 'Windows_NT'" />
</ItemGroup>
</Target>

<Target Name="_SetWasmBuildNativeDefaults">
<!-- if already set, maybe by a user projects, then a missing emsdk is an error -->
<Error Condition="'$(WasmBuildNative)' == 'true' and '$(_IsEMSDKMissing)' == 'true'"
Text="Cannot find emscripten sdk, required for building native files. %24(EMSDK_PATH)=$(EMSDK_PATH)" />
Text="$(_EMSDKMissingErrorMessage) Emscripten SDK is required for building native files." />

<Error Condition="'$(RunAOTCompilation)' == 'true' and '$(_IsEMSDKMissing)' == 'true'"
Text="Cannot find emscripten sdk, required for AOT'ing assemblies. %24(EMSDK_PATH)=$(EMSDK_PATH)" />
Text="$(_EMSDKMissingErrorMessage) Emscripten SDK is required for AOT'ing assemblies." />

<PropertyGroup>
<WasmBuildNative Condition="'$(RunAOTCompilation)' == 'true'">true</WasmBuildNative>
Expand All @@ -243,7 +342,7 @@

<!-- If we want to default to true, and sdk is missing, then just warn, and set it to false -->
<Warning Condition="'$(WasmBuildNative)' == 'true' and '$(_IsEMSDKMissing)' == 'true'"
Text="Cannot find emscripten sdk, required for building native files. %24(EMSDK_PATH)=$(EMSDK_PATH). Skipping native relinking" />
Text="$(_EMSDKMissingErrorMessage) Emscripten SDK is required for building native files." />

<PropertyGroup>
<WasmBuildNative Condition="'$(WasmBuildNative)' == 'true' and '$(_IsEMSDKMissing)' == 'true'">false</WasmBuildNative>
Expand Down Expand Up @@ -291,7 +390,7 @@
</Target>

<Target Name="_WasmBuildNative" DependsOnTargets="_WasmAotCompileApp;_WasmStripAOTAssemblies;_GenerateDriverGenC;_CheckEmccIsExpectedVersion" Condition="'$(WasmBuildNative)' == 'true'">
<Error Condition="'$(EMSDK_PATH)' == ''" Text="%24(EMSDK_PATH) should be set to emscripten sdk" />
<Error Condition="'$(EmscriptenSdkToolsPath)' == ''" Text="%24(EmscriptenSdkToolsPath) should be set to emscripten sdk" />

<PropertyGroup>
<EmccFlagsFile>$([MSBuild]::NormalizePath($(MicrosoftNetCoreAppRuntimePackRidNativeDir), 'src', 'emcc-flags.txt'))</EmccFlagsFile>
Expand Down Expand Up @@ -378,13 +477,13 @@
<EmccCFlags Condition="!$(_WasmIntermediateOutputPath.EndsWith('\'))">$(EmccCFlags) "-I$(_WasmIntermediateOutputPath)"</EmccCFlags>

<EmccLDFlags>$(EmccFlags) -s TOTAL_MEMORY=536870912</EmccLDFlags>
<_WasmOptCommand>$([MSBuild]::NormalizePath('$(EMSDK_PATH)', 'upstream', 'bin', 'wasm-opt$(_ExeExt)'))</_WasmOptCommand>
<_WasmOptCommand>$([MSBuild]::NormalizePath('$(EmSdkUpstreamBinPath)', 'wasm-opt$(_ExeExt)'))</_WasmOptCommand>
</PropertyGroup>

<Message Text="Compiling native assets with emcc. This may take a while ..." Importance="High" />
<RunWithEmSdkEnv Command='emcc $(EmccCFlags) "%(_WasmObjectsToBuild.SourcePath)" -c -o "%(_WasmObjectsToBuild.Identity)"' EmSdkPath="$(EMSDK_PATH)" />
<RunWithEmSdkEnv Command="emcc $(EmccLDFlags) @(_DotnetJSSrcFile->'--js-library &quot;%(Identity)&quot;', ' ') @(_BitcodeFile->'&quot;%(Identity)&quot;', ' ') @(_WasmObjects->'&quot;%(Identity)&quot;', ' ') -o &quot;$(_WasmIntermediateOutputPath)dotnet.js&quot;" EmSdkPath="$(EMSDK_PATH)" />
<RunWithEmSdkEnv Command='"$(_WasmOptCommand)" --strip-dwarf "$(_WasmIntermediateOutputPath)dotnet.wasm" -o "$(_WasmIntermediateOutputPath)dotnet.wasm"' Condition="'$(WasmNativeStrip)' == 'true'" IgnoreStandardErrorWarningFormat="true" EmSdkPath="$(EMSDK_PATH)" />
<Exec Command='emcc $(EmccCFlags) "%(_WasmObjectsToBuild.SourcePath)" -c -o "%(_WasmObjectsToBuild.Identity)"' EnvironmentVariables="@(EmscriptenEnvVars)" />
<Exec Command="emcc $(EmccLDFlags) @(_DotnetJSSrcFile->'--js-library &quot;%(Identity)&quot;', ' ') @(_BitcodeFile->'&quot;%(Identity)&quot;', ' ') @(_WasmObjects->'&quot;%(Identity)&quot;', ' ') -o &quot;$(_WasmIntermediateOutputPath)dotnet.js&quot;" EnvironmentVariables="@(EmscriptenEnvVars)" />
<Exec Command='"$(_WasmOptCommand)" --strip-dwarf "$(_WasmIntermediateOutputPath)dotnet.wasm" -o "$(_WasmIntermediateOutputPath)dotnet.wasm"' Condition="'$(WasmNativeStrip)' == 'true'" IgnoreStandardErrorWarningFormat="true" EnvironmentVariables="@(EmscriptenEnvVars)" />

<ItemGroup>
<WasmNativeAsset Include="$(_WasmIntermediateOutputPath)dotnet.wasm" />
Expand Down Expand Up @@ -435,9 +534,9 @@ EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_aot (const char *desc) { mono_
<Output TaskParameter="Lines" PropertyName="RuntimeEmccVersion" />
</ReadLinesFromFile>

<RunWithEmSdkEnv Command="emcc --version" WorkingDirectory="$(_WasmIntermediateOutputPath)" EmSdkPath="$(EMSDK_PATH)" ConsoleToMsBuild="true">
<Exec Command="emcc --version" WorkingDirectory="$(_WasmIntermediateOutputPath)" EnvironmentVariables="@(EmscriptenEnvVars)" ConsoleToMsBuild="true" StandardOutputImportance="Low">
<Output TaskParameter="ConsoleOutput" ItemName="_VersionLines" />
</RunWithEmSdkEnv>
</Exec>

<!-- we want to get the first line from the output, which has the version.
Rest of the lines are the license -->
Expand Down