Skip to content

[browser] fix emscripten out/err overrides #100630

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

Merged
merged 6 commits into from
Apr 9, 2024
Merged
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
2 changes: 1 addition & 1 deletion eng/testing/scenarios/BuildWasmAppsJobsList.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Wasm.Build.Tests.TestAppScenarios.AppSettingsTests
Wasm.Build.Tests.TestAppScenarios.LazyLoadingTests
Wasm.Build.Tests.TestAppScenarios.LibraryInitializerTests
Wasm.Build.Tests.TestAppScenarios.SatelliteLoadingTests
Wasm.Build.Tests.TestAppScenarios.DownloadResourceProgressTests
Wasm.Build.Tests.TestAppScenarios.ModuleConfigTests
Wasm.Build.Tests.TestAppScenarios.SignalRClientTests
Wasm.Build.Tests.WasmBuildAppTest
Wasm.Build.Tests.WasmNativeDefaultsTests
Expand Down
3 changes: 2 additions & 1 deletion src/mono/browser/runtime/loader/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { mono_exit } from "./exit";
import { addCachedReponse, findCachedResponse } from "./assetsCache";
import { getIcuResourceName } from "./icu";
import { makeURLAbsoluteWithApplicationBase } from "./polyfills";
import { mono_log_info } from "./logging";


let throttlingPromise: PromiseAndController<void> | undefined;
Expand Down Expand Up @@ -536,7 +537,7 @@ async function start_asset_download_sources (asset: AssetEntryInternal): Promise
err.status = response.status;
throw err;
} else {
loaderHelpers.out(`optional download '${response.url}' for ${asset.name} failed ${response.status} ${response.statusText}`);
mono_log_info(`optional download '${response.url}' for ${asset.name} failed ${response.status} ${response.statusText}`);
return undefined;
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/mono/browser/runtime/loader/icu.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import { mono_log_error } from "./logging";
import { GlobalizationMode, MonoConfig } from "../types";
import { ENVIRONMENT_IS_WEB, loaderHelpers } from "./globals";
import { mono_log_info, mono_log_debug } from "./logging";
Expand All @@ -18,7 +19,7 @@ export function init_globalization () {
loaderHelpers.preferredIcuAsset = null;
} else {
const msg = "invariant globalization mode is inactive and no ICU data archives are available";
loaderHelpers.err(`ERROR: ${msg}`);
mono_log_error(`ERROR: ${msg}`);
throw new Error(msg);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/mono/browser/runtime/loader/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ async function initializeModules (es6Modules: [RuntimeModuleExportsInternal, Nat
const { default: emscriptenFactory } = es6Modules[1];
setRuntimeGlobals(globalObjectsRoot);
initializeExports(globalObjectsRoot);
await configureRuntimeStartup();
await configureRuntimeStartup(emscriptenModule);
loaderHelpers.runtimeModuleLoaded.promise_control.resolve();

emscriptenFactory((originalModule: EmscriptenModuleInternal) => {
Expand Down
29 changes: 17 additions & 12 deletions src/mono/browser/runtime/startup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,23 @@ import { nativeAbort, nativeExit } from "./run";
import { mono_wasm_init_diagnostics } from "./diagnostics";
import { replaceEmscriptenPThreadInit } from "./pthreads/worker-thread";

export async function configureRuntimeStartup (): Promise<void> {
export async function configureRuntimeStartup (module: DotnetModuleInternal): Promise<void> {
if (!module.out) {
// eslint-disable-next-line no-console
module.out = console.log.bind(console);
}
if (!module.err) {
// eslint-disable-next-line no-console
module.err = console.error.bind(console);
}
if (!module.print) {
module.print = module.out;
}
if (!module.printErr) {
module.printErr = module.err;
}
loaderHelpers.out = module.print;
loaderHelpers.err = module.printErr;
await init_polyfills_async();
}

Expand All @@ -49,17 +65,6 @@ export function configureEmscriptenStartup (module: DotnetModuleInternal): void
module.locateFile = module.__locateFile = (path) => loaderHelpers.scriptDirectory + path;
}

if (!module.out) {
// eslint-disable-next-line no-console
module.out = console.log.bind(console);
}

if (!module.err) {
// eslint-disable-next-line no-console
module.err = console.error.bind(console);
}
loaderHelpers.out = module.out;
loaderHelpers.err = module.err;
module.mainScriptUrlOrBlob = loaderHelpers.scriptUrl;// this is needed by worker threads

// these all could be overridden on DotnetModuleConfig, we are chaing them to async below, as opposed to emscripten
Expand Down
4 changes: 3 additions & 1 deletion src/mono/browser/runtime/types/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,8 @@ export declare interface EmscriptenModuleInternal {
runtimeKeepalivePop(): void;
maybeExit(): void;
__emscripten_thread_init(pthread_ptr: PThreadPtr, isMainBrowserThread: number, isMainRuntimeThread: number, canBlock: number): void;
print(message: string): void;
printErr(message: string): void;
}

/// A PromiseController encapsulates a Promise together with easy access to its resolve and reject functions.
Expand Down Expand Up @@ -462,7 +464,7 @@ export type initializeExportsType = (globalObjects: GlobalObjects) => RuntimeAPI
export type initializeReplacementsType = (replacements: EmscriptenReplacements) => void;
export type afterInitializeType = (module: EmscriptenModuleInternal) => void;
export type configureEmscriptenStartupType = (module: DotnetModuleInternal) => void;
export type configureRuntimeStartupType = () => Promise<void>;
export type configureRuntimeStartupType = (module: DotnetModuleInternal) => Promise<void>;
export type configureWorkerStartupType = (module: DotnetModuleInternal) => Promise<void>


Expand Down
1 change: 1 addition & 0 deletions src/mono/sample/wasm/browser-advanced/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ try {
console.log('user code Module.onDotnetReady');
},
postRun: () => { console.log('user code Module.postRun'); },
out: (text) => { console.log("ADVANCED:" + text) },
})
.withResourceLoader((type, name, defaultUri, integrity, behavior) => {
// loadBootResource could return string with unqualified name of resource. It assumes that we resolve it with document.baseURI
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@

namespace Wasm.Build.Tests.TestAppScenarios;

public class DownloadResourceProgressTests : AppTestBase
public class ModuleConfigTests : AppTestBase
{
public DownloadResourceProgressTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
public ModuleConfigTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
{
}
Expand All @@ -25,7 +25,7 @@ public DownloadResourceProgressTests(ITestOutputHelper output, SharedBuildPerTes
[InlineData(true)]
public async Task DownloadProgressFinishes(bool failAssemblyDownload)
{
CopyTestAsset("WasmBasicTestApp", $"DownloadResourceProgressTests_{failAssemblyDownload}");
CopyTestAsset("WasmBasicTestApp", $"ModuleConfigTests_DownloadProgressFinishes_{failAssemblyDownload}");
PublishProject("Debug");

var result = await RunSdkStyleAppForPublish(new(
Expand Down Expand Up @@ -54,4 +54,24 @@ public async Task DownloadProgressFinishes(bool failAssemblyDownload)
: "The download progress test did emit unexpected message about failing download"
);
}

[Fact]
public async Task OutErrOverrideWorks()
{
CopyTestAsset("WasmBasicTestApp", $"ModuleConfigTests_OutErrOverrideWorks");
PublishProject("Debug");

var result = await RunSdkStyleAppForPublish(new(
Configuration: "Debug",
TestScenario: "OutErrOverrideWorks"
));
Assert.True(
result.ConsoleOutput.Any(m => m.Contains("Emscripten out override works!")),
"Emscripten out override doesn't work"
);
Assert.True(
result.ConsoleOutput.Any(m => m.Contains("Emscripten err override works!")),
"Emscripten err override doesn't work"
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
// The .NET Foundation licenses this file to you under the MIT license.

System.Console.WriteLine("WasmBasicTestApp");
System.Console.Error.WriteLine("WasmBasicTestApp stderr");
15 changes: 15 additions & 0 deletions src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ switch (testCase) {
}
});
break;
case "OutErrOverrideWorks":
dotnet.withModuleConfig({
out: (message) => {
console.log("Emscripten out override works!");
console.log(message)
},
err: (message) => {
console.error("Emscripten err override works!");
console.error(message)
},
});
break;
}

const { getAssemblyExports, getConfig, INTERNAL } = await dotnet.create();
Expand Down Expand Up @@ -97,6 +109,9 @@ try {
case "DownloadResourceProgressTest":
exit(0);
break;
case "OutErrOverrideWorks":
dotnet.run();
break;
case "DebugLevelTest":
testOutput("WasmDebugLevel: " + config.debugLevel);
exit(0);
Expand Down