From 0e579d07b9333669aae8d2e897b4d8d5d005b15a Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Tue, 8 Feb 2022 17:02:35 -0500 Subject: [PATCH] Wasm improvements --- IDE/src/BuildContext.bf | 154 +++++++++++++++++++------------- IDE/src/IDEApp.bf | 4 +- IDE/src/Project.bf | 34 ++++++- IDE/src/ui/ProjectProperties.bf | 13 +++ IDE/src/ui/SettingsDialog.bf | 16 ++++ bin/build_wasm.bat | 14 ++- 6 files changed, 169 insertions(+), 66 deletions(-) diff --git a/IDE/src/BuildContext.bf b/IDE/src/BuildContext.bf index 9635200e..cc119b6a 100644 --- a/IDE/src/BuildContext.bf +++ b/IDE/src/BuildContext.bf @@ -235,6 +235,8 @@ namespace IDE } arCmds.AppendF("SAVE\n"); + UpdateCacheStr(project, "", workspaceOptions, options, null, null); + if (project.mNeedsTargetRebuild) { if (File.Delete(targetPath) case .Err) @@ -468,6 +470,8 @@ namespace IDE } } + UpdateCacheStr(project, linkLine, workspaceOptions, options, depPaths, libPaths); + if (project.mNeedsTargetRebuild) { if (File.Delete(targetPath) case .Err) @@ -596,6 +600,8 @@ namespace IDE IDEUtils.AppendWithOptionalQuotes(linkLine, libPath); linkLine.Append(" "); } + + UpdateCacheStr(project, linkLine, workspaceOptions, options, depPaths, libPaths); if (project.mNeedsTargetRebuild) { @@ -621,32 +627,40 @@ namespace IDE #else String llvmDir = ""; #endif - if (!gApp.mSettings.mEmscriptenPath.IsEmpty) + if (gApp.mSettings.mEmscriptenPath.IsEmpty) + { + gApp.OutputErrorLine("Emscripten path not configured. Check Wasm configuration in File\\Preferences\\Settings."); + return false; + } + else { compilerExePath.Append(gApp.mSettings.mEmscriptenPath); if ((!compilerExePath.EndsWith('\\')) && (!compilerExePath.EndsWith('/'))) compilerExePath.Append("/"); } + + if (!File.Exists(scope $"{gApp.mInstallDir}/Beef{IDEApp.sRTVersionStr}RT32_wasm.a")) + { + gApp.OutputErrorLine("Wasm runtime libraries not found. Build with bin/build_wasm.bat."); + return false; + } + compilerExePath.Append(@"/upstream/emscripten/emcc.bat"); //linkLine.Append(" c:\\Beef\\wasm\\BeefRT.a -s STRICT=1 -s USE_PTHREADS=1 -s ALIASING_FUNCTION_POINTERS=1 -s ASSERTIONS=0 -s DISABLE_EXCEPTION_CATCHING=0 -s DEMANGLE_SUPPORT=0 -s EVAL_CTORS=1 -s WASM=1 -s \"EXPORTED_FUNCTIONS=['_BeefMain','_BeefDone','_pthread_mutexattr_init','_pthread_mutex_init','_emscripten_futex_wake','_calloc','_sbrk']\""); - linkLine.Append(" ", gApp.mInstallDir); - linkLine.Append("..\\..\\wasm\\BeefRT.a -s STRICT=1 -s USE_PTHREADS=1 -s ASSERTIONS=0 -s DISABLE_EXCEPTION_CATCHING=0 -s DEMANGLE_SUPPORT=0 -s WASM=1"); + linkLine.Append("-s DISABLE_EXCEPTION_CATCHING=0 -s DEMANGLE_SUPPORT=0 -s WASM=1"); - String workingDir = scope String(); - if (!llvmDir.IsEmpty) - { - workingDir.Append(llvmDir, "bin"); - } - else - { - workingDir.Append(gApp.mInstallDir); - } + if (project.mWasmOptions.mEnableThreads) + linkLine.Append(" -s USE_PTHREADS=1"); + + if (workspaceOptions.mEmitDebugInfo != .No) + linkLine.Append(" -g"); + + if (workspaceOptions.mRuntimeChecks) + linkLine.Append(" -s ASSERTIONS=1"); linkLine.Replace('\\', '/'); - //linkLine.Append(" --no-entry --export-all"); - - var runCmd = gApp.QueueRun(compilerExePath, linkLine, workingDir, .UTF8); + var runCmd = gApp.QueueRun(compilerExePath, linkLine, project.mProjectDir, .UTF8); runCmd.mOnlyIfNotFailed = true; var tagetCompletedCmd = new IDEApp.TargetCompletedCmd(project); tagetCompletedCmd.mOnlyIfNotFailed = true; @@ -845,6 +859,67 @@ namespace IDE } } + void UpdateCacheStr(Project project, StringView linkLine, Workspace.Options workspaceOptions, Project.Options options, List depPaths, List libPaths) + { + String cacheStr = scope String(); + + void AddBuildFileDependency(StringView filePath, bool resolveString = false) + { + var filePath; + + if ((resolveString) && (filePath.Contains('$'))) + { + String resolvedFilePath = scope:: String(); + gApp.ResolveConfigString(gApp.mPlatformName, workspaceOptions, project, options, filePath, "link flags", resolvedFilePath); + filePath = resolvedFilePath; + } + + int64 fileTime = 0; + if (!filePath.IsEmpty) + fileTime = File.GetLastWriteTime(filePath).GetValueOrDefault().ToFileTime(); + cacheStr.AppendF("{}\t{}\n", filePath, fileTime); + } + + cacheStr.AppendF("Args\t{}\n", linkLine); + cacheStr.AppendF("Toolset\t{}\n", workspaceOptions.mToolsetType); + AddBuildFileDependency(project.mWindowsOptions.mIconFile); + AddBuildFileDependency(project.mWindowsOptions.mManifestFile); + + switch (mPlatformType) + { + case .Windows: + cacheStr.AppendF("Description\t{}\n", project.mWindowsOptions.mDescription); + cacheStr.AppendF("Comments\t{}\n", project.mWindowsOptions.mComments); + cacheStr.AppendF("Company\t{}\n", project.mWindowsOptions.mCompany); + cacheStr.AppendF("Product\t{}\n", project.mWindowsOptions.mProduct); + cacheStr.AppendF("Copyright\t{}\n", project.mWindowsOptions.mCopyright); + cacheStr.AppendF("FileVersion\t{}\n", project.mWindowsOptions.mFileVersion); + cacheStr.AppendF("ProductVersion\t{}\n", project.mWindowsOptions.mProductVersion); + case .Linux: + cacheStr.AppendF("Options\t{}\n", project.mLinuxOptions.mOptions); + case .Wasm: + cacheStr.AppendF("EnableThreads\t{}\n", project.mWasmOptions.mEnableThreads); + default: + } + if (depPaths != null) + for (var linkDep in depPaths) + AddBuildFileDependency(linkDep, true); + if (libPaths != null) + for (var linkDep in libPaths) + AddBuildFileDependency(linkDep, true); + + String projectBuildDir = scope String(); + gApp.GetProjectBuildDir(project, projectBuildDir); + String prevCacheStr = scope .(); + gApp.mBfBuildCompiler.GetBuildValue(projectBuildDir, "Link", prevCacheStr); + if (prevCacheStr != cacheStr) + { + project.mNeedsTargetRebuild = true; + gApp.mBfBuildCompiler.SetBuildValue(projectBuildDir, "Link", cacheStr); + gApp.mBfBuildCompiler.WriteBuildCache(projectBuildDir); + } + } + bool QueueProjectMSLink(Project project, String targetPath, String configName, Workspace.Options workspaceOptions, Project.Options options, String objectsArg) { bool is64Bit = mPtrSize == 8; @@ -1006,54 +1081,13 @@ namespace IDE let winOptions = project.mWindowsOptions; - String cacheStr = scope String(); - - void AddBuildFileDependency(StringView filePath, bool resolveString = false) - { - var filePath; - - if ((resolveString) && (filePath.Contains('$'))) - { - String resolvedFilePath = scope:: String(); - gApp.ResolveConfigString(gApp.mPlatformName, workspaceOptions, project, options, filePath, "link flags", resolvedFilePath); - filePath = resolvedFilePath; - } - - int64 fileTime = 0; - if (!filePath.IsEmpty) - fileTime = File.GetLastWriteTime(filePath).GetValueOrDefault().ToFileTime(); - cacheStr.AppendF("{}\t{}\n", filePath, fileTime); - } - - cacheStr.AppendF("Args\t{}\n", linkLine); - cacheStr.AppendF("Toolset\t{}\n", workspaceOptions.mToolsetType); - AddBuildFileDependency(project.mWindowsOptions.mIconFile); - AddBuildFileDependency(project.mWindowsOptions.mManifestFile); - cacheStr.AppendF("Description\t{}\n", project.mWindowsOptions.mDescription); - cacheStr.AppendF("Comments\t{}\n", project.mWindowsOptions.mComments); - cacheStr.AppendF("Company\t{}\n", project.mWindowsOptions.mCompany); - cacheStr.AppendF("Product\t{}\n", project.mWindowsOptions.mProduct); - cacheStr.AppendF("Copyright\t{}\n", project.mWindowsOptions.mCopyright); - cacheStr.AppendF("FileVersion\t{}\n", project.mWindowsOptions.mFileVersion); - cacheStr.AppendF("ProductVersion\t{}\n", project.mWindowsOptions.mProductVersion); - for (var linkDep in depPaths) - AddBuildFileDependency(linkDep, true); - for (var linkDep in libPaths) - AddBuildFileDependency(linkDep, true); - - String projectBuildDir = scope String(); - gApp.GetProjectBuildDir(project, projectBuildDir); - String prevCacheStr = scope .(); - gApp.mBfBuildCompiler.GetBuildValue(projectBuildDir, "Link", prevCacheStr); - if (prevCacheStr != cacheStr) - { - project.mNeedsTargetRebuild = true; - gApp.mBfBuildCompiler.SetBuildValue(projectBuildDir, "Link", cacheStr); - gApp.mBfBuildCompiler.WriteBuildCache(projectBuildDir); - } + UpdateCacheStr(project, linkLine, workspaceOptions, options, depPaths, libPaths); if (project.mNeedsTargetRebuild) { + String projectBuildDir = scope String(); + gApp.GetProjectBuildDir(project, projectBuildDir); + if ((!String.IsNullOrWhiteSpace(project.mWindowsOptions.mIconFile)) || (!String.IsNullOrWhiteSpace(project.mWindowsOptions.mManifestFile)) || (winOptions.HasVersionInfo())) diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 7e0865fb..ed6d216a 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -9662,10 +9662,10 @@ namespace IDE case .Linux: newString.AppendF("./{} -lpthread -ldl -Wl,-rpath -Wl,$ORIGIN", rtName); case .Wasm: - /*newString.Append(mInstallDir); + newString.Append(mInstallDir); newString.Append("Beef", IDEApp.sRTVersionStr, "RT"); newString.Append((Workspace.PlatformType.GetPtrSizeByName(gApp.mPlatformName) == 4) ? "32" : "64"); - newString.Append("_wasm.lib");*/ + newString.Append("_wasm.a"); default: } diff --git a/IDE/src/Project.bf b/IDE/src/Project.bf index c8d157bf..ed6c5e02 100644 --- a/IDE/src/Project.bf +++ b/IDE/src/Project.bf @@ -1058,6 +1058,22 @@ namespace IDE } } + public class WasmOptions + { + [Reflect] + public bool mEnableThreads = true; + + public void Deserialize(StructuredData data) + { + mEnableThreads = data.GetBool("EnableThreads", true); + } + + public void Serialize(StructuredData data) + { + data.ConditionalAdd("EnableThreads", mEnableThreads, true); + } + } + public class GeneralOptions { [Reflect] @@ -1338,6 +1354,7 @@ namespace IDE // Platform-dependent options public WindowsOptions mWindowsOptions = new WindowsOptions() ~ delete _; public LinuxOptions mLinuxOptions = new LinuxOptions() ~ delete _; + public WasmOptions mWasmOptions = new WasmOptions() ~ delete _; public List mDependencies = new List() ~ DeleteContainerAndItems!(_); public bool mLastDidBuild; @@ -1625,6 +1642,12 @@ namespace IDE data.RemoveIfEmpty(); } + using (data.CreateObject("Wasm")) + { + mWasmOptions.Serialize(data); + data.RemoveIfEmpty(); + } + data.RemoveIfEmpty(); } @@ -1655,7 +1678,8 @@ namespace IDE { case .Linux, .Windows, - .macOS: + .macOS, + .Wasm: defaultBuildKind = isTest ? .Test : .Normal; default: defaultBuildKind = .StaticLib; @@ -1942,6 +1966,8 @@ namespace IDE mWindowsOptions.Deserialize(data); using (data.Open("Linux")) mLinuxOptions.Deserialize(data); + using (data.Open("Wasm")) + mWasmOptions.Deserialize(data); } if (!data.Contains("Dependencies")) @@ -2009,7 +2035,8 @@ namespace IDE { case .Linux, .Windows, - .macOS: + .macOS, + .Wasm: defaultBuildKind = isTest ? .Test : .Normal; default: defaultBuildKind = .StaticLib; @@ -2410,7 +2437,8 @@ namespace IDE { case .Linux, .Windows, - .macOS: + .macOS, + .Wasm: options.mBuildOptions.mBuildKind = isTest ? .Test : .Normal; default: options.mBuildOptions.mBuildKind = .StaticLib; diff --git a/IDE/src/ui/ProjectProperties.bf b/IDE/src/ui/ProjectProperties.bf index bbc35e9c..f53b8e55 100644 --- a/IDE/src/ui/ProjectProperties.bf +++ b/IDE/src/ui/ProjectProperties.bf @@ -507,6 +507,7 @@ namespace IDE.ui { case .Windows: mCurPropertiesTargets[0] = mProject.mWindowsOptions; case .Linux: mCurPropertiesTargets[0] = mProject.mLinuxOptions; + case .Wasm: mCurPropertiesTargets[0] = mProject.mWasmOptions; default: } } @@ -594,6 +595,7 @@ namespace IDE.ui { case .Windows: PopulateWindowsOptions(); case .Linux: PopulateLinuxOptions(); + case .Wasm: PopulateWasmOptions(); default: } } @@ -661,6 +663,17 @@ namespace IDE.ui category.Open(true, true); } + void PopulateWasmOptions() + { + var root = (DarkListViewItem)mPropPage.mPropertiesListView.GetRoot(); + var (category, ?) = AddPropertiesItem(root, "General"); + category.mIsBold = true; + category.mTextColor = Color.Mult(DarkTheme.COLOR_TEXT, 0xFFE8E8E8); + AddPropertiesItem(category, "Enable Threads", "mEnableThreads"); + //parent.MakeParent(); + category.Open(true, true); + } + void PopulateBuildOptions() { var root = (DarkListViewItem)mPropPage.mPropertiesListView.GetRoot(); diff --git a/IDE/src/ui/SettingsDialog.bf b/IDE/src/ui/SettingsDialog.bf index d052ffda..842cdcda 100644 --- a/IDE/src/ui/SettingsDialog.bf +++ b/IDE/src/ui/SettingsDialog.bf @@ -17,6 +17,7 @@ namespace IDE.ui Compiler, Debugger, VisualStudio, + Wasm, COUNT } @@ -60,6 +61,7 @@ namespace IDE.ui AddCategoryItem(root, "Compiler"); AddCategoryItem(root, "Debugger"); AddCategoryItem(root, "Visual Studio"); + AddCategoryItem(root, "Wasm"); if (!gApp.mSettings.mVSSettings.IsConfigured()) gApp.mSettings.mVSSettings.SetDefaults(); @@ -145,6 +147,18 @@ namespace IDE.ui category.Open(true, true); } + void PopulateWasmOptions() + { + mCurPropertiesTarget = gApp.mSettings; + + var root = (DarkListViewItem)mPropPage.mPropertiesListView.GetRoot(); + var (category, propEntry) = AddPropertiesItem(root, "General"); + category.mIsBold = true; + category.mTextColor = Color.Mult(DarkTheme.COLOR_TEXT, cHeaderColor); + AddPropertiesItem(category, "Emscripten Path", "mEmscriptenPath", null, .BrowseForFolder); + category.Open(true, true); + } + void CommandContextToString(IDECommand.ContextFlags contextFlags, String str) { bool isFirst = true; @@ -376,6 +390,8 @@ namespace IDE.ui PopulateDebuggerOptions(); case .VisualStudio: PopulateVSOptions(); + case .Wasm: + PopulateWasmOptions(); default: /*mCurPropertiesTarget = gApp.mSettings.mEditorSettings; PopulateEditorOptions();*/ diff --git a/bin/build_wasm.bat b/bin/build_wasm.bat index c7db0417..0209807d 100644 --- a/bin/build_wasm.bat +++ b/bin/build_wasm.bat @@ -1,4 +1,16 @@ mkdir ..\wasm cd ..\wasm call emcc ..\BeefRT\rt\Math.cpp ..\BeefRT\rt\Object.cpp ..\BeefRT\rt\Thread.cpp ..\BeefRT\rt\Internal.cpp ..\BeefySysLib\platform\wasm\WasmCommon.cpp ..\BeefySysLib\Common.cpp ..\BeefySysLib\util\String.cpp ..\BeefySysLib\util\UTF8.cpp ..\BeefySysLib\third_party\utf8proc\utf8proc.c -I..\ -I..\BeefySysLib -I..\BeefySysLib\platform\wasm -g -DBF_DISABLE_FFI -c -s WASM=1 -s USE_PTHREADS=1 -emar r BeefRT.a Common.o Internal.o Math.o Object.o String.o Thread.o UTF8.o utf8proc.o WasmCommon.o \ No newline at end of file +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +call emar r ..\IDE\dist\Beef042RT32_wasm.a Common.o Internal.o Math.o Object.o String.o Thread.o UTF8.o utf8proc.o WasmCommon.o +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR + +:SUCCESS +@ECHO SUCCESS! +@POPD +@EXIT /b 0 + +:HADERROR +@ECHO =================FAILED================= +@POPD +@EXIT /b %ERRORLEVEL%