[wasm] WasmApp.targets: Separate `obj`, and `bin` parts of the build process (#47253)
authorAnkit Jain <radical@gmail.com>
Mon, 25 Jan 2021 22:53:51 +0000 (17:53 -0500)
committerGitHub <noreply@github.com>
Mon, 25 Jan 2021 22:53:51 +0000 (17:53 -0500)
We want to use a separate directory for intermediate build outputs, that aren't needed
in the app bundle, and reduce unclear internal dependencies during a build.

# TL;DR

## Changes:
1. `$(WasmBuildDir)` removed
2. Reasonable defaults set for most properties
3. To generate a wasm app for a project, the minimum you need to set:
    a. `$(WasmMainJS)`,
    b. and `@(WasmAssembliesToBundle)`

# Details:

Though it is a bit tricky, because the current targets assume:

- that they are being run after `Publish`
- that the publish directory has:
  - some required files copied over from the runtime pack (eg. `libmono*`),
  - and includes the assemblies
- that the targets emit all the intermediate output files like `driver.o`, or the bitcode files, into the same
   directory

- And there are assumptions about where to pick which files from (eg. whether to take `dotnet.wasm`
  from the runtime pack, or from the publish dir), based on unclear rules.

## What does this PR change?

- All the assets meant to be from the runtime pack (like `libmono*`, `icudt.dat`) are always taken
  only from the runtime pack
  - and this logic is moved out of the tasks, to the targets
- `$(WasmBuildDir)` is removed completely. Instead, we use an intermediate path based on `$(IntermediateOutputPath)`
  - and emit all the intermediate bits there, like the bitcode files
- Add reasonable defaults for various properties, like `$(WasmAppDir)`

Effectively:

1. To generate a wasm app for a project, the minimum you need to set:
    a. `$(WasmMainJS)`,
    b. and `@(WasmAssembliesToBundle)`

2. The targets don't depend on publish dir at all
    (in a future PR, we could remove triggering based on `Publish` target also)
* [wasm] WasmAppBuilder - move the list of native assets, and logic out

.. to the targets.

- New property: `NativeAssets`, populated by `@(WasmNativeAsset)`
- Remove property `MicrosoftNetCoreAppRuntimePackRidDir`
- Also, add the `icudt.dat` file from the targets

* [wasm] Simplify handling of dotnet.{js,wasm}

WasmAppBuilder has (non-obvious) logic to:

1. if AOT'ing, then use the *generated* dotnet.{js,wasm};
2. else use the one from the runtime pack

This depends on Publish having copied those files from the runtime pack
to the publish directory, and then comparing paths in the builder to
decide which one to use.

Instead, make this the intention obvious, and clear.

----
Commits:
* [wasm] Always get the native libs from the runtime pack (eg.libmono*)

We were getting these from the publish directory, instead we can get
them directly from the runtime pack.

This includes icudt.dt, and dotnet.timezones.blat .

* [wasm] MonoAOTCompiler: add `OutputDir` property

.. where we can emit the generated native files. Since these files are
meant only for generating the final `dotnet.wasm`, we don't want them to
put them in the bin directory.

* [wasm] Use existing list of assemblies - @(_WasmAssemblies)

.. instead of trying to find them in the build dir. This build directory
will become a directory for intermediate build output in upcoming
commits.

* [wasm] Replace $(WasmMainAssemblyPath) with $(WasmMainAssemblyFileName)

- Instead of having a special $(WasmMainAssemblyPath), and then adding
  it to the wasm assemblies ourselves
  - let the user project add all the relevant assemblies to
    `@(WasmAssembliesToBundle)`, which is usually as simple as
    `$(OutDir)\*.dll`.

- This helps to simplify lot of things.
- And we just need the main assembly filename for generating the
  run-v8.sh script.

* [wasm] Rename WasmBuildDir -> _WasmIntermediateOutputPath

Based on the changes in previous commits, we can now remove
`$(WasmBuildDir)`, and replace that with an internal
`$(_WasmIntermediateOutputPath)`. This path will have all the build
artifacts generated that aren't required in the app bundle.

Earlier, we were using the publish directory for that, which resulted in
it being littered with unncessary files, and files getting copied to the
app bundle from unclear sources, and for non-obvious reasons.

* [wasm] add default value for $(WasmAppDir)

* [wasm] WasmApp.targets - misc cleanup

* [wasm] WasmAppBuilder: validate Assemblies property

* [wasm] WasmTestRunner - rename TestAssembly->TestAssemblyFileName, to correctly reflect the value

* [wasm] Fix make clean, for samples

* [wasm] WasmApp.targets: Add new $(MonoAotCrossCompilerPath)

* [wasm] update comments/docs

* Address review feedback from @mdh1418

15 files changed:
eng/testing/tests.mobile.targets
src/mono/netcore/sample/mbr/browser/WasmDelta.csproj
src/mono/netcore/sample/wasm/Directory.Build.targets
src/mono/netcore/sample/wasm/wasm.mk
src/mono/wasm/build/README.md
src/mono/wasm/build/WasmApp.InTree.targets
src/mono/wasm/build/WasmApp.targets
src/mono/wasm/debugger/tests/debugger-test/debugger-test.csproj
src/tasks/AotCompilerTask/MonoAOTCompiler.cs
src/tasks/WasmAppBuilder/WasmAppBuilder.cs
src/tests/Common/CLRTest.Execute.Bash.targets
src/tests/Common/wasm-test-runner/WasmTestRunner.proj
src/tests/FunctionalTests/wasm/AOT/browser/Wasm.Aot.Browser.Test.csproj
src/tests/FunctionalTests/wasm/Directory.Build.targets
src/tests/FunctionalTests/wasm/Interpreter/browser/Wasm.Interpreter.Browser.Test.csproj

index cf57079..31e2a3a 100644 (file)
   <Target Condition="'$(TargetOS)' == 'Browser'" Name="PrepareForWasmBuildApp">
     <PropertyGroup>
       <WasmAppDir>$(BundleDir)</WasmAppDir>
-      <WasmBuildDir>$(PublishDir)</WasmBuildDir>
-      <WasmMainAssemblyPath Condition="'$(WasmMainAssemblyPath)' == ''">$(PublishDir)WasmTestRunner.dll</WasmMainAssemblyPath>
+      <WasmMainAssemblyFileName Condition="'$(WasmMainAssemblyFileName)' == ''">WasmTestRunner.dll</WasmMainAssemblyFileName>
       <WasmMainJSPath Condition="'$(WasmMainJSPath)' == ''">$(MonoProjectRoot)\wasm\runtime-test.js</WasmMainJSPath>
       <WasmInvariantGlobalization>$(InvariantGlobalization)</WasmInvariantGlobalization>
       <WasmGenerateRunV8Script>true</WasmGenerateRunV8Script>
index 92ee7ca..322a01b 100644 (file)
   </ItemGroup>
 
   <Target Name="PrepareDeltasForWasmApp" DependsOnTargets="Build;CompileDiff;ComputeDeltaFileOutputNames">
-    <PropertyGroup>
-      <WasmBuildDir>$(MSBuildProjectDirectory)\$(PublishDir)\</WasmBuildDir>
-      <WasmMainAssemblyPath>$(WasmBuildDir)$(AssemblyName).dll</WasmMainAssemblyPath>
-    </PropertyGroup>
-
     <ItemGroup>
       <WasmAssembliesToBundle Include="$(TargetDir)publish\*.dll" />
       <WasmFilesToIncludeInFileSystem Include="@(_DeltaFileForPublish)">
index e2c0589..640ae9b 100644 (file)
@@ -6,10 +6,6 @@
   </PropertyGroup>
 
   <Target Name="PrepareForWasmBuild">
-    <PropertyGroup>
-      <WasmBuildDir>$(MSBuildProjectDirectory)\$(PublishDir)\</WasmBuildDir>
-      <WasmMainAssemblyPath>$(WasmBuildDir)$(AssemblyName).dll</WasmMainAssemblyPath>
-    </PropertyGroup>
     <ItemGroup>
       <WasmAssembliesToBundle Include="$(TargetDir)publish\*.dll" />
     </ItemGroup>
index a6b2725..1858ca3 100644 (file)
@@ -16,7 +16,7 @@ build:
        EMSDK_PATH=$(realpath $(TOP)/src/mono/wasm/emsdk) $(DOTNET) publish $(DOTNET_Q_ARGS) $(WASM_DEFAULT_BUILD_ARGS) $(MSBUILD_ARGS) $(PROJECT_NAME)
 
 clean:
-       rm -rf bin $(TOP)/artifacts/obj/mono/$(PROJECT_NAME)
+       rm -rf bin $(TOP)/artifacts/obj/mono/$(PROJECT_NAME:%.csproj=%)
 
 run-browser:
        if ! $(DOTNET) tool list --global | grep dotnet-serve; then \
index e8343ab..c019c01 100644 (file)
@@ -47,3 +47,5 @@ The various task inputs correspond to properties as:
     - To control it's generation use `$(WasmGenerateRunV8Script)` (false by default)
 
 This should be a step towards eventually having this build as a sdk.
+
+Refer to `WasmApp.targets` for more information about the properties/items used as inputs to the process.
index c5191b6..7f1f355 100644 (file)
@@ -10,7 +10,7 @@
         <PackageDirectory>$(ArtifactsBinDir)microsoft.netcore.app.runtime.browser-wasm\$(Configuration)</PackageDirectory>
       </RuntimePack>
     </ItemGroup>
-    <Message Text="RuntimePack.PackageDirectory: %(RuntimePack.PackageDirectory)" Importance="high" />
+    <Message Text="Using RuntimePack.PackageDirectory: %(RuntimePack.PackageDirectory)" Importance="Low" />
   </Target>
 
   <Target Name="RebuildWasmAppBuilder">
index 18afa16..2357b0f 100644 (file)
@@ -6,14 +6,14 @@
   <UsingTask TaskName="PInvokeTableGenerator" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" />
 
   <!--
-      Public properties (required):
-      - $(WasmBuildDir)    - Directory where build artifacts are stored (required if WasmBuildNative==true)
-      - $(WasmAppDir)      - AppBundle dir
-      - $(WasmMainAssemblyPath)
+      Required public items/properties:
       - $(WasmMainJSPath)
+      - @(WasmAssembliesToBundle)    - list of assemblies to package as the wasm app
       - $(EMSDK_PATH)      - points to the emscripten sdk location.
 
       Public properties (optional):
+      - $(WasmAppDir)        - AppBundle dir (Defaults to `$(OutputPath)\$(Configuration)\AppBundle`)
+      - $(WasmMainAssemblyFileName)- Defaults to $(TargetFileName)
       - $(WasmBuildNative)   - Whenever to build the native executable. Defaults to false.
       - $(WasmNativeStrip)   - Whenever to strip the native executable. Defaults to true.
       - $(RunAOTCompilation) - Defaults to false.
       - $(WasmSkipMissingAssemblies)        - Don't fail on any missing dependencies
 
       Public items:
-      - @(WasmExtraFilesToDeploy) - Files to copy to $(WasmBuildDir).
+      - @(WasmExtraFilesToDeploy) - Files to copy to $(WasmAppDir).
                                     (relative path can be set via %(TargetPath) metadata)
       - @(WasmSatelliteAssemblies)
       - @(WasmFilesToIncludeInFileSystem) - Files to include in the vfs
+      - @(WasmNativeAsset)        - Native files to be added to `NativeAssets` in the bundle.
 
       - @(WasmExtraConfig)        - json elements to add to `mono-config.js`
                                     Eg. <WasmExtraConfig Include="enable_profiler" Value="true" />
@@ -53,6 +54,9 @@
   <Target Name="WasmBuildApp" AfterTargets="Publish" />
 
   <Target Name="_WasmAotCompileApp" Condition="'$(RunAOTCompilation)' == 'true'">
+    <Error Condition="'@(_WasmAssemblies)' == ''" Text="Item _WasmAssemblies is empty" />
+    <Error Condition="'$(EMSDK_PATH)' == ''" Text="%24(EMSDK_PATH) should be set to emscripten sdk" />
+
     <ItemGroup>
       <MonoAOTCompilerDefaultAotArguments Include="no-opt" />
       <MonoAOTCompilerDefaultAotArguments Include="static" />
     <PropertyGroup>
       <AOTMode Condition="'$(AOTMode)' == '' and '$(AOTProfilePath)' != ''">AotInterp</AOTMode>
       <AOTMode Condition="'$(AOTMode)' == ''">LLVMOnly</AOTMode>
+      <MonoAotCrossCompilerPath Condition="'$(MonoAotCrossCompilerPath)' == ''">$(MicrosoftNetCoreAppRuntimePackRidDir)native\cross\$(PackageRID)\mono-aot-cross</MonoAotCrossCompilerPath>
     </PropertyGroup>
 
     <MonoAOTCompiler
-      CompilerBinaryPath="$(MicrosoftNetCoreAppRuntimePackRidDir)native\cross\$(PackageRID)\mono-aot-cross"
+      CompilerBinaryPath="$(MonoAotCrossCompilerPath)"
+      OutputDir="$(_WasmIntermediateOutputPath)"
       Mode="$(AOTMode)"
       OutputType="AsmOnly"
       Assemblies="@(_AotInputAssemblies)"
       UseAotDataFile="false"
       AOTProfilePath="$(AOTProfilePath)"
       Profilers="$(WasmProfilers)"
-      AotModulesTablePath="$(WasmBuildDir)driver-gen.c"
+      AotModulesTablePath="$(_WasmIntermediateOutputPath)driver-gen.c"
       UseLLVM="true"
       DisableParallelAot="true"
       LLVMPath="$(EMSDK_PATH)\upstream\bin">
   </Target>
 
   <Target Name="_BeforeWasmBuildApp">
-      <Error Condition="'$(WasmMainAssemblyPath)' == ''" Text="%24(WasmMainAssemblyPath) property needs to be set" />
-      <Error Condition="!Exists('$(WasmMainAssemblyPath)')" Text="WasmMainAssemblyPath=$(WasmMainAssemblyPath) does not exist" />
-      <Error Condition="'$(WasmAppDir)' == ''" Text="%24(WasmAppDir) property needs to be set" />
-      <Error Condition="'$(WasmBuildNative)' == 'true' and '$(WasmBuildDir)' == ''" Text="%24(WasmBuildDir) property needs to be set" />
-      <Error Condition="!Exists('$(MicrosoftNetCoreAppRuntimePackRidDir)')" Text="MicrosoftNetCoreAppRuntimePackRidDir=$(MicrosoftNetCoreAppRuntimePackRidDir) doesn't exist" />
-      <Error Condition="'$(WasmMainJSPath)' == ''" Text="%24(WasmMainJSPath) property needs to be set" />
-      <ItemGroup>
-          <_WasmAssemblies Include="$(WasmMainAssemblyPath);@(WasmAssembliesToBundle)" />
-      </ItemGroup>
+    <Error Condition="'$(IntermediateOutputPath)' == ''" Text="%24(IntermediateOutputPath) property needs to be set" />
+    <Error Condition="!Exists('$(MicrosoftNetCoreAppRuntimePackRidDir)')" Text="MicrosoftNetCoreAppRuntimePackRidDir=$(MicrosoftNetCoreAppRuntimePackRidDir) doesn't exist" />
+    <Error Condition="'$(WasmMainJSPath)' == ''" Text="%24(WasmMainJSPath) property needs to be set" />
+
+    <PropertyGroup>
+      <WasmAppDir Condition="'$(WasmAppDir)' == ''">$(OutputPath)AppBundle\</WasmAppDir>
+      <WasmMainAssemblyFileName Condition="'$(WasmMainAssemblyFileName)' == ''">$(TargetFileName)</WasmMainAssemblyFileName>
+      <_WasmIntermediateOutputPath>$(IntermediateOutputPath)\wasm\</_WasmIntermediateOutputPath>
+    </PropertyGroup>
+
+    <MakeDir Directories="$(_WasmIntermediateOutputPath)" />
+    <PropertyGroup>
+      <MicrosoftNetCoreAppRuntimePackRidDir Condition="!HasTrailingSlash('$(MicrosoftNetCoreAppRuntimePackRidDir)')">$(MicrosoftNetCoreAppRuntimePackRidDir)\</MicrosoftNetCoreAppRuntimePackRidDir>
+    </PropertyGroup>
+    <ItemGroup>
+        <_WasmAssemblies Include="@(WasmAssembliesToBundle)" />
+    </ItemGroup>
   </Target>
 
   <Target Name="_WasmBuildApp" BeforeTargets="WasmBuildApp" DependsOnTargets="$(WasmBuildAppDependsOn)">
+    <PropertyGroup>
+      <WasmIcuDataFileName Condition="'$(WasmInvariantGlobalization)' != 'true'">icudt.dat</WasmIcuDataFileName>
+
+      <_HasDotnetWasm Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.wasm'">true</_HasDotnetWasm>
+      <_HasDotnetJs Condition="'%(WasmNativeAsset.FileName)%(WasmNativeAsset.Extension)' == 'dotnet.js'">true</_HasDotnetJs>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <!-- If dotnet.{wasm,js} weren't added already (eg. AOT can add them), then add the default ones -->
+      <WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidDir)native\dotnet.wasm" Condition="'$(_HasDotnetWasm)' != 'true'" />
+      <WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidDir)native\dotnet.js" Condition="'$(_HasDotnetJs)' != 'true'" />
+
+      <WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidDir)native\$(WasmIcuDataFileName)" Condition="'$(WasmInvariantGlobalization)' != 'true'" />
+      <WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidDir)native\dotnet.timezones.blat" />
+    </ItemGroup>
+
     <WasmAppBuilder
       AppDir="$(WasmAppDir)"
-      MicrosoftNetCoreAppRuntimePackDir="$(MicrosoftNetCoreAppRuntimePackRidDir)"
       MainJS="$(WasmMainJSPath)"
       Assemblies="@(_WasmAssemblies)"
       InvariantGlobalization="$(WasmInvariantGlobalization)"
       RemoteSources="@(WasmRemoteSources)"
       ExtraFilesToDeploy="@(WasmExtraFilesToDeploy)"
       ExtraConfig="@(WasmExtraConfig)"
+      NativeAssets="@(WasmNativeAsset)"
       DebugLevel="$(WasmDebugLevel)">
       <Output TaskParameter="FileWrites" ItemName="FileWrites" />
     </WasmAppBuilder>
     <PropertyGroup>
       <EmccFlagsFile>$(MicrosoftNetCoreAppRuntimePackRidDir)native\src\emcc-flags.txt</EmccFlagsFile>
       <RuntimeEmccVersionFile>$(MicrosoftNetCoreAppRuntimePackRidDir)native\src\emcc-version.txt</RuntimeEmccVersionFile>
-      <EmccPublishVersionFile>$(WasmBuildDir)emcc-version.txt</EmccPublishVersionFile>
+      <EmccPublishVersionFile>$(_WasmIntermediateOutputPath)emcc-version.txt</EmccPublishVersionFile>
     </PropertyGroup>
     <ReadLinesFromFile File="$(EmccFlagsFile)">
         <Output TaskParameter="Lines" PropertyName="_DefaultEmccFlags" />
         <Output TaskParameter="Lines" PropertyName="RuntimeEmccVersion" />
     </ReadLinesFromFile>
 
-    <Exec Command="bash -c '$(_EmccCommand) --version | head -1 > emcc-version.txt'" IgnoreStandardErrorWarningFormat="true" WorkingDirectory="$(WasmBuildDir)" />
+    <Exec Command="bash -c '$(_EmccCommand) --version | head -1 > emcc-version.txt'" IgnoreStandardErrorWarningFormat="true" WorkingDirectory="$(_WasmIntermediateOutputPath)" />
     <ReadLinesFromFile File="$(EmccPublishVersionFile)">
         <Output TaskParameter="Lines" PropertyName="EmccVersion" />
     </ReadLinesFromFile>
       <_WasmPInvokeModules Include="libSystem.Native" />
       <_WasmPInvokeModules Include="libSystem.IO.Compression.Native" />
       <_WasmPInvokeModules Include="libSystem.Globalization.Native" />
-      <_WasmPInvokeAssemblies Include="$(WasmBuildDir)\*.dll" />
    </ItemGroup>
-   <!--This pinvoke-table.h will be used instead of the one in the runtime pack because of -I$(WasmBuildDir) -->
+   <!--This pinvoke-table.h will be used instead of the one in the runtime pack because of -I$(_WasmIntermediateOutputPath) -->
    <PInvokeTableGenerator
      Modules="@(_WasmPInvokeModules)"
-     Assemblies="@(_WasmPInvokeAssemblies)"
-     OutputPath="$(WasmBuildDir)pinvoke-table.h" />
+     Assemblies="@(_WasmAssemblies)"
+     OutputPath="$(_WasmIntermediateOutputPath)pinvoke-table.h" />
 
    <ItemGroup>
-     <_WasmObjects Include="libmono-ee-interp.a"/>
-     <_WasmObjects Include="libmonosgen-2.0.a"/>
-     <_WasmObjects Include="libmono-ilgen.a"/>
-     <_WasmObjects Include="libmono-icall-table.a"/>
-     <_WasmObjects Include="libSystem.Native.a"/>
-     <_WasmObjects Include="libSystem.IO.Compression.Native.a"/>
-     <_WasmObjects Include="libmono-profiler-aot.a"/>
-     <_WasmObjects Include="libicuuc.a"/>
-     <_WasmObjects Include="libicui18n.a"/>
+     <_WasmRuntimePackNativeLibs Include="libmono-ee-interp.a"/>
+     <_WasmRuntimePackNativeLibs Include="libmonosgen-2.0.a"/>
+     <_WasmRuntimePackNativeLibs Include="libmono-ilgen.a"/>
+     <_WasmRuntimePackNativeLibs Include="libmono-icall-table.a"/>
+     <_WasmRuntimePackNativeLibs Include="libSystem.Native.a"/>
+     <_WasmRuntimePackNativeLibs Include="libSystem.IO.Compression.Native.a"/>
+     <_WasmRuntimePackNativeLibs Include="libmono-profiler-aot.a"/>
+     <_WasmRuntimePackNativeLibs Include="libicuuc.a"/>
+     <_WasmRuntimePackNativeLibs Include="libicui18n.a"/>
+     <_WasmObjects Include="@(_WasmRuntimePackNativeLibs->'$(MicrosoftNetCoreAppRuntimePackRidDir)\native\%(FileName)%(Extension)')" />
+
      <_WasmObjects Include="driver.o"/>
      <_WasmObjects Include="pinvoke.o"/>
      <_WasmObjects Include="corebindings.o"/>
    <PropertyGroup>
      <_WasmIncludeDir>$(MicrosoftNetCoreAppRuntimePackRidDir)native/include</_WasmIncludeDir>
      <_WasmSrcDir>$(MicrosoftNetCoreAppRuntimePackRidDir)native/src</_WasmSrcDir>
-     <EmccCFlags>$(EmccFlags) -DCORE_BINDINGS -DGEN_PINVOKE=1 -I$(WasmBuildDir) -I$(_WasmIncludeDir)/mono-2.0 -I$(_WasmIncludeDir)/wasm</EmccCFlags>
+     <EmccCFlags>$(EmccFlags) -DCORE_BINDINGS -DGEN_PINVOKE=1 -I$(_WasmIntermediateOutputPath) -I$(_WasmIncludeDir)/mono-2.0 -I$(_WasmIncludeDir)/wasm</EmccCFlags>
      <EmccLDFlags>$(EmccFlags) -s TOTAL_MEMORY=536870912</EmccLDFlags>
    </PropertyGroup>
 
-    <Exec Command="bash -c '$(_EmccCommand) $(EmccCFlags) $(_WasmSrcDir)/driver.c -c -o driver.o'" IgnoreStandardErrorWarningFormat="true" WorkingDirectory="$(WasmBuildDir)" StandardOutputImportance="Low" />
-    <Exec Command="bash -c '$(_EmccCommand) $(EmccCFlags) $(_WasmSrcDir)/corebindings.c -c -o corebindings.o'" IgnoreStandardErrorWarningFormat="true" WorkingDirectory="$(WasmBuildDir)" StandardOutputImportance="Low" />
-    <Exec Command="bash -c '$(_EmccCommand) $(EmccCFlags) $(_WasmSrcDir)/pinvoke.c -c -o pinvoke.o'" IgnoreStandardErrorWarningFormat="true" WorkingDirectory="$(WasmBuildDir)" StandardOutputImportance="Low" />
-    <Exec Command="bash -c '$(_EmccCommand) $(EmccLDFlags) --js-library $(_WasmSrcDir)/library_mono.js --js-library $(_WasmSrcDir)/binding_support.js --js-library $(_WasmSrcDir)/dotnet_support.js --js-library $(_WasmSrcDir)/pal_random.js @(_WasmAssemblies->'%(LlvmBitcodeFile)', ' ') @(_WasmObjects, ' ') -o dotnet.js'" IgnoreStandardErrorWarningFormat="true" WorkingDirectory="$(WasmBuildDir)" StandardOutputImportance="Low" />
-    <Exec Condition="'$(WasmNativeStrip)' == 'true'" Command="bash -c '$(EMSDK_PATH)/upstream/bin/wasm-opt --strip-dwarf dotnet.wasm -o dotnet.wasm'" IgnoreStandardErrorWarningFormat="true" WorkingDirectory="$(WasmBuildDir)" />
+    <Exec Command="bash -c '$(_EmccCommand) $(EmccCFlags) $(_WasmSrcDir)/driver.c -c -o driver.o'" IgnoreStandardErrorWarningFormat="true" WorkingDirectory="$(_WasmIntermediateOutputPath)" StandardOutputImportance="Low" />
+    <Exec Command="bash -c '$(_EmccCommand) $(EmccCFlags) $(_WasmSrcDir)/corebindings.c -c -o corebindings.o'" IgnoreStandardErrorWarningFormat="true" WorkingDirectory="$(_WasmIntermediateOutputPath)" StandardOutputImportance="Low" />
+    <Exec Command="bash -c '$(_EmccCommand) $(EmccCFlags) $(_WasmSrcDir)/pinvoke.c -c -o pinvoke.o'" IgnoreStandardErrorWarningFormat="true" WorkingDirectory="$(_WasmIntermediateOutputPath)" StandardOutputImportance="Low" />
+    <Exec Command="bash -c '$(_EmccCommand) $(EmccLDFlags) --js-library $(_WasmSrcDir)/library_mono.js --js-library $(_WasmSrcDir)/binding_support.js --js-library $(_WasmSrcDir)/dotnet_support.js --js-library $(_WasmSrcDir)/pal_random.js @(_WasmAssemblies->'%(LlvmBitcodeFile)', ' ') @(_WasmObjects, ' ') -o dotnet.js'" IgnoreStandardErrorWarningFormat="true" WorkingDirectory="$(_WasmIntermediateOutputPath)" StandardOutputImportance="Low" />
+    <Exec Condition="'$(WasmNativeStrip)' == 'true'" Command="bash -c '$(EMSDK_PATH)/upstream/bin/wasm-opt --strip-dwarf dotnet.wasm -o dotnet.wasm'" IgnoreStandardErrorWarningFormat="true" WorkingDirectory="$(_WasmIntermediateOutputPath)" />
+
+    <ItemGroup>
+      <WasmNativeAsset Include="$(_WasmIntermediateOutputPath)\dotnet.wasm" />
+      <WasmNativeAsset Include="$(_WasmIntermediateOutputPath)\dotnet.js" />
+    </ItemGroup>
   </Target>
 
   <Target Name="_GenerateDriverGenC" Condition="'$(RunAOTCompilation)' != 'true' and '$(WasmProfilers)' != ''">
@@ -222,7 +258,7 @@ void mono_profiler_init_aot (const char *desc)%3B
 EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_aot (const char *desc) { mono_profiler_init_aot (desc)%3B }
       </InitAotProfilerCmd>
 
-      <_DriverGenCPath>$(WasmBuildDir)driver-gen.c</_DriverGenCPath>
+      <_DriverGenCPath>$(_WasmIntermediateOutputPath)driver-gen.c</_DriverGenCPath>
     </PropertyGroup>
 
     <Message Text="Generating $(_DriverGenCPath)" Importance="Low" />
@@ -238,9 +274,10 @@ EMSCRIPTEN_KEEPALIVE void mono_wasm_load_profiler_aot (const char *desc) { mono_
       <WasmRunV8ScriptPath Condition="'$(WasmRunV8ScriptPath)' == ''">$(WasmAppDir)run-v8.sh</WasmRunV8ScriptPath>
     </PropertyGroup>
 
+    <Error Condition="'$(WasmMainAssemblyFileName)' == ''" Text="%24(WasmMainAssemblyFileName) property needs to be set for generating $(WasmRunV8ScriptPath)." />
     <WriteLinesToFile
       File="$(WasmRunV8ScriptPath)"
-      Lines="v8 --expose_wasm runtime.js -- --run $([System.IO.Path]::GetFileName('$(WasmMainAssemblyPath)')) $*"
+      Lines="v8 --expose_wasm runtime.js -- --run $(WasmMainAssemblyFileName) $*"
       Overwrite="true">
     </WriteLinesToFile>
 
index 91e81ae..988b3b2 100644 (file)
@@ -19,7 +19,6 @@
 
   <Target Name="PrepareForWasmBuildApp" DependsOnTargets="RebuildWasmAppBuilder;Build">
     <PropertyGroup>
-      <WasmMainAssemblyPath>$(OutDir)debugger-test.dll</WasmMainAssemblyPath>
       <WasmAppDir>$(AppDir)</WasmAppDir>
       <WasmMainJSPath>$(MonoProjectRoot)wasm\runtime-test.js</WasmMainJSPath>
       <WasmDebugLevel>1</WasmDebugLevel>
@@ -28,6 +27,7 @@
     </PropertyGroup>
 
     <ItemGroup>
+      <WasmAssembliesToBundle Include="$(OutDir)\$(TargetFileName)" />
       <WasmAssemblySearchPaths Include="$(MicrosoftNetCoreAppRuntimePackRidDir)native"/>
       <WasmAssemblySearchPaths Include="$(MicrosoftNetCoreAppRuntimePackRidDir)lib\$(NetCoreAppCurrent)"/>
 
index c3a5bb3..b7c0cf3 100644 (file)
@@ -4,6 +4,7 @@
 using System;
 using System.Collections.Generic;
 using System.Collections.Concurrent;
+using System.Diagnostics.CodeAnalysis;
 using System.IO;
 using System.Linq;
 using System.Text;
@@ -30,6 +31,13 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
     public ITaskItem[] Assemblies { get; set; } = Array.Empty<ITaskItem>();
 
     /// <summary>
+    /// Directory where the AOT'ed files will be emitted
+    /// </summary>
+    [NotNull]
+    [Required]
+    public string? OutputDir { get; set; }
+
+    /// <summary>
     /// Assemblies which were AOT compiled.
     ///
     /// Successful AOT compilation will set the following metadata on the items:
@@ -133,6 +141,12 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
             throw new ArgumentException($"'{nameof(Assemblies)}' is required.", nameof(Assemblies));
         }
 
+        if (!Directory.Exists(OutputDir))
+        {
+            Log.LogError($"OutputDir={OutputDir} doesn't exist");
+            return false;
+        }
+
         if (!string.IsNullOrEmpty(AotProfilePath) && !File.Exists(AotProfilePath))
         {
             Log.LogError($"'{AotProfilePath}' doesn't exist.", nameof(AotProfilePath));
@@ -242,12 +256,14 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
             processArgs.Add("--nollvm");
         }
 
+        string assemblyFilename = Path.GetFileName(assembly);
+
         // compute output mode and file names
         if (parsedAotMode == MonoAotMode.LLVMOnly || parsedAotMode == MonoAotMode.AotInterp)
         {
             aotArgs.Add("llvmonly");
 
-            string llvmBitcodeFile = Path.ChangeExtension(assembly, ".dll.bc");
+            string llvmBitcodeFile = Path.Combine(OutputDir, Path.ChangeExtension(assemblyFilename, ".dll.bc"));
             aotAssembly.SetMetadata("LlvmBitcodeFile", llvmBitcodeFile);
 
             if (parsedAotMode == MonoAotMode.AotInterp)
@@ -276,20 +292,20 @@ public class MonoAOTCompiler : Microsoft.Build.Utilities.Task
             {
                 aotArgs.Add("asmonly");
 
-                string assemblerFile = Path.ChangeExtension(assembly, ".dll.s");
+                string assemblerFile = Path.Combine(OutputDir, Path.ChangeExtension(assemblyFilename, ".dll.s"));
                 aotArgs.Add($"outfile={assemblerFile}");
                 aotAssembly.SetMetadata("AssemblerFile", assemblerFile);
             }
             else
             {
-                string objectFile = Path.ChangeExtension(assembly, ".dll.o");
+                string objectFile = Path.Combine(OutputDir, Path.ChangeExtension(assemblyFilename, ".dll.o"));
                 aotArgs.Add($"outfile={objectFile}");
                 aotAssembly.SetMetadata("ObjectFile", objectFile);
             }
 
             if (UseLLVM)
             {
-                string llvmObjectFile = Path.ChangeExtension(assembly, ".dll-llvm.o");
+                string llvmObjectFile = Path.Combine(OutputDir, Path.ChangeExtension(assemblyFilename, ".dll-llvm.o"));
                 aotArgs.Add($"llvm-outfile={llvmObjectFile}");
                 aotAssembly.SetMetadata("LlvmObjectFile", llvmObjectFile);
             }
index d43a09d..de7c0e3 100644 (file)
@@ -24,15 +24,15 @@ public class WasmAppBuilder : Task
 
     [NotNull]
     [Required]
-    public string? MicrosoftNetCoreAppRuntimePackDir { get; set; }
+    public string? MainJS { get; set; }
 
     [NotNull]
     [Required]
-    public string? MainJS { get; set; }
+    public string[]? Assemblies { get; set; }
 
     [NotNull]
     [Required]
-    public string[]? Assemblies { get; set; }
+    public ITaskItem[]? NativeAssets { get; set; }
 
     private List<string> _fileWrites = new();
 
@@ -41,7 +41,7 @@ public class WasmAppBuilder : Task
 
     // full list of ICU data files we produce can be found here:
     // https://github.com/dotnet/icu/tree/maint/maint-67/icu-filters
-    public string? IcuDataFileName { get; set; } = "icudt.dat";
+    public string? IcuDataFileName { get; set; }
 
     public int DebugLevel { get; set; }
     public ITaskItem[]? SatelliteAssemblies { get; set; }
@@ -127,22 +127,18 @@ public class WasmAppBuilder : Task
             throw new ArgumentException($"File MainJS='{MainJS}' doesn't exist.");
         if (!InvariantGlobalization && string.IsNullOrEmpty(IcuDataFileName))
             throw new ArgumentException("IcuDataFileName property shouldn't be empty if InvariantGlobalization=false");
-        if (Assemblies == null)
+
+        if (Assemblies?.Length == 0)
         {
-            Log.LogError($"Assemblies should not be null.");
+            Log.LogError("Cannot build Wasm app without any assemblies");
             return false;
         }
 
         var _assemblies = new List<string>();
-        var runtimeSourceDir = Path.Join(MicrosoftNetCoreAppRuntimePackDir, "native");
-
-        foreach (var asm in Assemblies)
+        foreach (var asm in Assemblies!)
         {
             if (!_assemblies.Contains(asm))
                 _assemblies.Add(asm);
-
-            if (asm.EndsWith("System.Private.CoreLib.dll"))
-                runtimeSourceDir = Path.GetDirectoryName(asm);
         }
 
         var config = new WasmAppConfig ();
@@ -163,15 +159,11 @@ public class WasmAppBuilder : Task
             }
         }
 
-        List<string> nativeAssets = new List<string>() { "dotnet.wasm", "dotnet.js", "dotnet.timezones.blat" };
-
-        if (!InvariantGlobalization)
-            nativeAssets.Add(IcuDataFileName!);
-
-        if (Path.TrimEndingDirectorySeparator(Path.GetFullPath(runtimeSourceDir)) != Path.TrimEndingDirectorySeparator(Path.GetFullPath(AppDir!)))
+        foreach (ITaskItem item in NativeAssets)
         {
-            foreach (var f in nativeAssets)
-                FileCopyChecked(Path.Join(runtimeSourceDir, f), Path.Join(AppDir, f), "NativeAssets");
+            string dest = Path.Combine(AppDir!, Path.GetFileName(item.ItemSpec));
+            if (!FileCopyChecked(item.ItemSpec, dest, "NativeAssets"))
+                return false;
         }
         FileCopyChecked(MainJS!, Path.Join(AppDir, "runtime.js"), string.Empty);
 
@@ -278,7 +270,7 @@ public class WasmAppBuilder : Task
             }
         }
 
-        return true;
+        return !Log.HasLoggedErrors;
     }
 
     private bool TryParseExtraConfigValue(ITaskItem extraItem, out object? valueObject)
index d7b4830..cf2bdfe 100644 (file)
@@ -274,7 +274,7 @@ else
   __Command+=" dotnet"
 fi
 
-$__Command msbuild $CORE_ROOT/wasm-test-runner/WasmTestRunner.proj /p:NetCoreAppCurrent=$(NetCoreAppCurrent) /p:TestAssembly=`pwd`/$(MsBuildProjectName).dll /p:TestBinDir=`pwd` || exit $?
+$__Command msbuild $CORE_ROOT/wasm-test-runner/WasmTestRunner.proj /p:NetCoreAppCurrent=$(NetCoreAppCurrent) /p:TestAssemblyFileName=$(MsBuildProjectName).dll /p:TestBinDir=`pwd` || exit $?
 
    ]]>
       </BashCLRTestPreCommands>
index 99c21b0..c28b704 100644 (file)
@@ -16,7 +16,7 @@
 
   <Target Name="BuildApp" BeforeTargets="WasmBuildApp">
     <PropertyGroup>
-      <WasmMainAssemblyPath>$(TestAssembly)</WasmMainAssemblyPath>
+      <WasmMainAssemblyFileName>$(TestAssemblyFileName)</WasmMainAssemblyFileName>
       <WasmAppDir>$(AppDir)</WasmAppDir>
       <WasmMainJSPath>$(CORE_ROOT)\runtime-test\runtime-test.js</WasmMainJSPath>
       <WasmResolveAssembliesBeforeBuild>true</WasmResolveAssembliesBeforeBuild>
@@ -25,6 +25,7 @@
     </PropertyGroup>
 
     <ItemGroup>
+      <WasmAssembliesToBundle Include="$(TestBinDir)\*.dll" />
       <WasmAssembliesToBundle Include="$(CORE_ROOT)\System.Private.Runtime.InteropServices.JavaScript.dll" />
       <WasmAssemblySearchPaths Include="$(MicrosoftNetCoreAppRuntimePackRidDir)\native"/>
       <WasmAssemblySearchPaths Include="$(MicrosoftNetCoreAppRuntimePackRidDir)"/>
index 0a84ee7..bd206a8 100644 (file)
@@ -3,6 +3,7 @@
     <RunAOTCompilation>true</RunAOTCompilation>
     <Scenario>WasmTestOnBrowser</Scenario>
     <ExpectedExitCode>42</ExpectedExitCode>
+    <WasmMainJSPath>runtime.js</WasmMainJSPath>
   </PropertyGroup>
 
   <ItemGroup>
   <Target Name="AfterWasmBuildApp" AfterTargets="WasmBuildApp">
     <Copy SourceFiles="$(OutDir)\index.html" DestinationFolder="$(WasmAppDir)" />
   </Target>
-
-  <Target Name="SetMainAssemblyPath" BeforeTargets="Publish">
-    <PropertyGroup>
-      <WasmMainAssemblyPath>$(PublishDir)Wasm.AOT.Browser.Test.dll</WasmMainAssemblyPath>
-      <WasmMainJSPath>runtime.js</WasmMainJSPath>
-    </PropertyGroup>
-  </Target>
 </Project>
index 55390cd..b0d320f 100644 (file)
@@ -3,14 +3,10 @@
 
   <PropertyGroup>
     <WasmBuildAppDependsOn>PrepareForWasmBuild;$(WasmBuildAppDependsOn)</WasmBuildAppDependsOn>
+    <WasmAppDir>$(OutputPath)\$(Configuration)\AppBundle\</WasmAppDir>
   </PropertyGroup>
 
   <Target Name="PrepareForWasmBuild">
-    <PropertyGroup>
-      <WasmAppDir>$(OutputPath)\$(Configuration)\AppBundle\</WasmAppDir>
-      <WasmBuildDir>$(PublishDir)</WasmBuildDir>
-      <WasmMainAssemblyPath>$(WasmBuildDir)$(AssemblyName).dll</WasmMainAssemblyPath>
-    </PropertyGroup>
     <ItemGroup>
       <WasmAssembliesToBundle Include="$(TargetDir)publish\*.dll" />
     </ItemGroup>
index 47c4c6c..db384e0 100644 (file)
@@ -5,6 +5,7 @@
     <TestRuntime>true</TestRuntime>
     <Scenario>WasmTestOnBrowser</Scenario>
     <ExpectedExitCode>42</ExpectedExitCode>
+    <WasmMainJSPath>runtime.js</WasmMainJSPath>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="Program.cs" />
   <Target Name="AfterWasmBuildApp" AfterTargets="WasmBuildApp">
     <Copy SourceFiles="$(OutDir)\index.html" DestinationFolder="$(WasmAppDir)" />
   </Target>
-
-  <Target Name="SetMainAssemblyPath" BeforeTargets="Publish">
-    <PropertyGroup>
-      <WasmMainAssemblyPath>$(PublishDir)Wasm.Interpreter.Browser.Test.dll</WasmMainAssemblyPath>
-      <WasmMainJSPath>runtime.js</WasmMainJSPath>
-    </PropertyGroup>
-  </Target>
 </Project>