From bfc22654262e182f4b32f4d713bc05a2d57f61be Mon Sep 17 00:00:00 2001 From: ASDAlexander77 Date: Mon, 14 Sep 2026 21:45:24 +0100 Subject: [PATCH 1/2] Build the native wrappers with the CRT tslang links against build_core.bat compiled io/datetime/regex/thread/http.cpp without a runtime library flag, so cl used its default /MT (static release CRT) for the debug build as well. A debug tslang program (--di, no --opt) links the debug archive together with the static debug CRT (libcmtd, _ITERATOR_DEBUG_LEVEL=2), so `tslang --emit=exe` against lib\debug\\TypeScriptDefaultLib.lib failed with LNK2038 RuntimeLibrary / _ITERATOR_DEBUG_LEVEL mismatches in TypeScriptDefaultLib.lib(datetime.obj). This is what failed test-compile-gc-defaultlib-collector in a debug TypeScriptCompiler build. Debug now passes /MTd; release passes /MT explicitly (unchanged behaviour). Co-Authored-By: Claude Opus 5 --- scripts/build_core.bat | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/build_core.bat b/scripts/build_core.bat index 2be681d..cafb91e 100644 --- a/scripts/build_core.bat +++ b/scripts/build_core.bat @@ -26,7 +26,12 @@ rem live inside each .obj. /Zi would park it in an external vc140.pdb in the cur rem which is never staged next to the .lib and is overwritten by the next memory model's build, rem leaving consumers unable to step into io.cpp/datetime.cpp/etc. This matches what tslang's rem --di already does for the .ts objects. -set DBG_CL=/Z7 /std:c++latest +rem /MTd, /MT: the wrappers' C runtime has to match the one tslang links against. A debug program +rem (--di, no --opt) picks this debug archive and links the static debug CRT (libcmtd, +rem _ITERATOR_DEBUG_LEVEL=2); an --opt program picks the release archive and the static release CRT +rem (see tslang/tslang/exe.cpp). Without a flag cl defaults to /MT, so the debug archive carried +rem release-CRT wrappers and a debug `tslang --emit=exe` against it failed with LNK2038 mismatches. +set DBG_CL=/MTd /Z7 /std:c++latest set TOOL_NAME=tslang if "%1"=="release" ( @@ -35,7 +40,7 @@ if "%1"=="release" ( set BUILD1=release set LLVM_BUILD=Release set DBG=--opt --opt_level=3 - set DBG_CL=/std:c++latest + set DBG_CL=/MT /std:c++latest ) rem Memory model (%2). The default library is not model-neutral: under gc it allocates through From 6d6956f919d6a14dc666719137fdd22bc6bf22e3 Mon Sep 17 00:00:00 2001 From: Alex D Date: Tue, 22 Sep 2026 18:08:08 +0100 Subject: [PATCH 2/2] Build and test the default library for 32-bit Windows (TSLANG_ARCH=x86) (#8) * Build the default library for 32-bit Windows with TSLANG_ARCH=x86 Set TSLANG_ARCH=x86 before build.bat to stage the x86 tree (defaultlib/{lib,dll}/x86/{debug,release}/{gc,rc,none}/) alongside the existing x64 one. build_core.bat now picks vcvarsall's arch argument, passes -mtriple=i686-pc-windows-msvc to every tslang.exe invocation, and routes every output/staging path through one LIB_OUT/DLL_OUT pair per arch. The x86 LLVM toolchain needs an explicit clang-cl -m32, applied after the arch is known; the where-on-PATH check keeps checking the bare tool name via TSLANG_CC_TOOL. The x86 DLL link needs an explicit --tslang-lib-path into the tslang-runtime tree, since the default TSLANG_LIB_PATH points at the compiler's own build output, which has no x86 subdirectory; GC_SHARED_LIB_PATH stays the flat x64 tree on purpose, since tslang appends "x86" to it itself. Verified: all 6 x86 combos (release/debug x gc/rc/none) build and stage as COFF machine 0x14c, including the gc.dll import for the gc model; the x86 LLVM toolchain path also produces genuine i386 objects; x64 behavior is unchanged for both TSLANG_ARCH=x64 and TSLANG_ARCH unset. Co-Authored-By: Claude Opus 5 * Name the x86 runtime library as a prerequisite of the x86 build README.md documented only the x86 Boehm GC prerequisite for TSLANG_ARCH=x86. The x86 DLL build also links TypeScriptAsyncRuntime.lib via the --tslang-lib-path build_core.bat now passes, and that x86 lib has no default build step of its own - it comes from scripts\build_tslang_runtime__x86.bat in the compiler repo. List it alongside the Boehm GC prerequisite. Co-Authored-By: Claude Opus 5 * Run the default-library tests as 32-bit programs with TSLANG_ARCH=x86 Under TSLANG_ARCH=x86, tests.ps1 compiles each test with -mtriple=i686-pc-windows-msvc, drops --shared-libs=...TypeScriptRuntime.dll (an x64 JIT-only DLL that --emit=exe never reads), and passes --gc-lib-path/--tslang-lib-path explicitly at the x64 build trees under TypeScriptCompiler so the compiler's own x86 append can't be shadowed by an x64 value already sitting in the session's environment. The JIT is host-only by design, so only the two compile passes run for x86; the script prints "jit is host-only; skipped for x86" and skips both jit passes. x64 behavior (all four passes) is unchanged. Verified: x86 release/compile and debug/compile both 149/150, with string_replaceAll segfaulting in both (known probe finding, fixed in a later task). x64 before and after this change produced byte-for-byte identical results (306/600 failed, same breakdown), so the pre-existing x64 release/debug compile-mode linker failures (unresolved llvm::deallocate_buffer / llvm::StdThreadPool from TypeScriptAsyncRuntime.lib) and the 6 known debug/jit date_* failures are unrelated to this change. Co-Authored-By: Claude Opus 5 * Pass the default-library path explicitly for the x86 test run The x86 branch already passed --gc-lib-path/--tslang-lib-path explicitly so a stale x64 value in the environment couldn't leak in, but relied on DEFAULT_LIB_PATH isolation being accidental: it only worked because the pre-existing $Env:DEFAULT_LIB_PAT typo a few lines up always fails its null check, forcing $Env:DEFAULT_LIB_PATH to be set fresh on every call. Fixing that typo later would let a stale x64 DEFAULT_LIB_PATH leak into the x86 pass. Add --default-lib-path=$DEFAULTLIB_BUILD_PATH to $ARCH_ARGS for x86 - the same value the script already computes - so the isolation is deliberate, matching gc/tslang. The typo itself is left alone; x64 behavior is unchanged (the else branch is untouched). Co-Authored-By: Claude Opus 5 * Pass the replacement to regexp_replace in RegExp.replaceAll RegExp.replaceAll called the native regexp_replace(expr, flags, s, replacement) with three arguments; the compiler does not check the arity of the declared native function and passed `ptr undef` for the fourth. At x64 the undef lives in r9, which happened to still hold the caller's replacement, so the call worked by accident. At i686 the fourth argument is an uninitialised stack slot, so std::regex_replace read a garbage pointer and the program crashed (string_replaceAll segfaulted at x86). Co-Authored-By: Claude Opus 5 * Address final review: per-tree COMPILER_VERSION, clearing TSLANG_ARCH, x86 path notes COMPILER_VERSION.txt was shared and truncated by whichever arch built last; build_core.bat now writes a separate COMPILER_VERSION.x86.txt for x86 while keeping the x64 file name (and output) unchanged. README.md documents how and why to clear TSLANG_ARCH after an x86 build. tests.ps1 gets a comment noting its x86 block assumes the sibling TypeScriptCompiler layout and ignores $Env:TOOL_PATH for the gc/runtime lib paths. Co-Authored-By: Claude Opus 5 --------- Co-authored-by: Claude Opus 5 --- README.md | 44 ++++++++++++++ build.bat | 7 +++ scripts/build_core.bat | 128 ++++++++++++++++++++++++++++------------- scripts/build_llvm.bat | 6 +- src/lib.ts | 2 +- tests.ps1 | 45 +++++++++++++-- 6 files changed, 186 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 0703848..9ffb4bc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,50 @@ # TypeScriptCompilerDefaultLib Implementation of Default Core Library for TypeScript Compiler +## Building + +``` +build.bat # x64, release and debug, all three memory models +build.bat release gc # x64, just that one +``` + +For 32-bit Windows, set `TSLANG_ARCH=x86` before calling `build.bat` (it is an +environment variable, not a positional argument, the same idiom as `TSLANG_TOOLCHAIN`): + +``` +set TSLANG_ARCH=x86 +build.bat +``` + +Clear it afterwards - `set TSLANG_ARCH=` (or `Remove-Item Env:TSLANG_ARCH` in +PowerShell) - since it is a session-wide environment variable, not a +one-shot argument: a later plain `build.bat` or `tslang --install-default-lib` +run in the same shell would otherwise silently build only the x86 tree. + +This stages into `__build\defaultlib\{lib,dll}\x86\\\`, +alongside the existing x64 tree. It requires two things already built in the compiler +repo: + +- the x86 Boehm GC: `prepare_3rdParty.bat x86` in `TypeScriptCompiler`; +- the x86 `TypeScriptAsyncRuntime.lib`, which the DLL build links: + `scripts\build_tslang_runtime__x86.bat` in `TypeScriptCompiler`, which + puts it in `__build\tslang-runtime\\x86\`. + +## Testing + +``` +tests.ps1 # x64, all four passes: release/debug x compile/jit +$Env:TSLANG_ARCH="x86"; .\tests.ps1 # x86, release/compile and debug/compile only +``` + +The JIT is host-only (`--emit=jit` refuses an x86 target by design), so under +`TSLANG_ARCH=x86` `tests.ps1` prints "jit is host-only; skipped for x86" and runs only +the two compile passes, against the x86 tree built above. It compiles with +`-mtriple=i686-pc-windows-msvc` and points `--gc-lib-path`/`--tslang-lib-path` at the x64 +build trees under `TypeScriptCompiler` (the compiler appends `x86` to each itself), so an +x64 value already set in `$Env:GC_LIB_PATH`/`$Env:TSLANG_LIB_PATH` for the session can't +leak into the x86 build. + ## Docs - [fetch / Headers / Response](docs/fetch.md) — built-in HTTP client diff --git a/build.bat b/build.bat index 86296eb..326e74e 100644 --- a/build.bat +++ b/build.bat @@ -9,6 +9,13 @@ @rem of cl/lib.exe; everything else (flags, layout, output tree) is identical, so the two @rem builds are interchangeable and overwrite each other in lib\ and dll\. @rem +@rem Set TSLANG_ARCH=x86 to build the 32-bit tree instead of the default x64 one, e.g. +@rem set TSLANG_ARCH=x86 +@rem build.bat release gc +@rem Like TSLANG_TOOLCHAIN, it is an environment variable, not a positional argument - +@rem %1/%2 stay "mode model" either way. x86 stages into lib\x86\... and dll\x86\..., +@rem alongside the x64 tree, and needs the x86 Boehm GC prerequisite (see README.md). +@rem @rem See tslang/include/TypeScript/Defines.h for the resulting layout. if /I "%TSLANG_TOOLCHAIN%" == "llvm" ( diff --git a/scripts/build_core.bat b/scripts/build_core.bat index cafb91e..f542137 100644 --- a/scripts/build_core.bat +++ b/scripts/build_core.bat @@ -6,7 +6,8 @@ rem rem %1 release | debug (default: debug) rem %2 memory model (default: gc) rem -rem The caller sets TSLANG_CC / TSLANG_AR / TSLANG_TOOLCHAIN. +rem The caller sets TSLANG_CC / TSLANG_AR / TSLANG_TOOLCHAIN. TSLANG_ARCH (x64 | x86, +rem default x64) picks the target architecture; see the ARCH block below. echo on @@ -19,7 +20,30 @@ set VER=-2026 set BUILD=debug set BUILD1=Debug set LLVM_BUILD=Debug -set ARCH=x64 +if "%TSLANG_ARCH%"=="" set TSLANG_ARCH=x64 +set ARCH=%TSLANG_ARCH% +if not "%ARCH%"=="x64" if not "%ARCH%"=="x86" ( + echo "" + echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + echo "XXX TSLANG_ARCH must be x64 or x86 XXX" + echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + echo "" + exit /b 1 +) +rem ARCH_DIR nests the x86 tree one level under lib\ and dll\, next to today's flat +rem x64 layout (defaultlib/{lib,dll}/x86/...; see tslang/include/TypeScript/Defines.h). +rem TRIPLE_OPT tells tslang.exe to target i686 instead of its host x64. +set ARCH_DIR= +set TRIPLE_OPT= +if "%ARCH%"=="x86" ( + set ARCH_DIR=\x86 + set TRIPLE_OPT=-mtriple=i686-pc-windows-msvc +) +rem clang-cl targets x64 regardless of which vcvarsall was called, so an x86 LLVM build +rem needs an explicit -m32. TSLANG_CC_TOOL keeps the bare executable name (no flags) for +rem the "where" check below - "where" cannot resolve "clang-cl -m32" as one token. +set TSLANG_CC_TOOL=%TSLANG_CC% +if "%TSLANG_TOOLCHAIN%"=="llvm" if "%ARCH%"=="x86" set "TSLANG_CC=%TSLANG_CC% -m32" set DBG=--di --opt_level=0 rem /Z7, not /Zi: the wrappers are archived into a static .lib, so their debug info has to rem live inside each .obj. /Zi would park it in an external vc140.pdb in the current directory, @@ -51,6 +75,19 @@ set MM=gc if not "%2"=="" set MM=%2 set MM_OPT=-mm=%MM% +rem One variable per output tree, set once here and used everywhere below (rd, md, /Fo, +rem -o, --obj, del, xcopy, the final exist check), so an x86 build never lands a file in +rem the x64 tree by way of a spot that forgot to add ARCH_DIR. +set LIB_OUT=lib%ARCH_DIR%\%BUILD%\%MM% +set DLL_OUT=dll%ARCH_DIR%\%BUILD%\%MM% + +rem The DLL build below links TypeScriptAsyncRuntime.lib. TSLANG_LIB_PATH (set further +rem down) defaults to the compiler's own build tree, which has no x86 subdirectory, so +rem an x86 build points --tslang-lib-path at the separate tslang-runtime tree instead +rem (tslang appends "x86" to it itself, same as --gc-lib-path). +set TSLANG_RUNTIME_OPT= +if "%ARCH%"=="x86" set TSLANG_RUNTIME_OPT=--tslang-lib-path=..\TypeScriptCompiler\__build\tslang-runtime\%BUILD% + set SRC=. set OUTPUT=. @@ -70,8 +107,11 @@ rem binary - TypeScriptRuntime.dll under the JIT, a user's shared library - and rem would give it a collector of its own that frees what they hold. The static lib\ archive rem links no collector at all, so it is unaffected. rem See TypeScriptCompiler/tslang/docs/single-gc-collector-design.md. +rem Always the x64 gcdll tree, even for an x86 build (%ARCH% deliberately not used here): +rem tslang appends "x86" to --gc-lib-path itself when the target is x86, so this path +rem must stay the flat x64 one or that segment would be doubled. if "%GC_SHARED_LIB_PATH%"=="" ( - set GC_SHARED_LIB_PATH=..\TypeScriptCompiler\3rdParty\gcdll\%ARCH%\%BUILD%\lib + set GC_SHARED_LIB_PATH=..\TypeScriptCompiler\3rdParty\gcdll\x64\%BUILD%\lib ) if "%LLVM_LIB_PATH%"=="" ( set LLVM_LIB_PATH=%BUILD_PATH%\llvm\msbuild\%ARCH%\%BUILD%\%BUILD1%\lib @@ -105,20 +145,22 @@ if "%VSWHERE_PATH%"=="" ( set "VSWHERE_PATH=%VSWHERE_PATH:"=%" +rem vcvarsall.bat takes the target arch as its argument (x64 or x86) - both live in the +rem same VC\Auxiliary\Build directory as the old arch-specific vcvars64.bat. for /f "usebackq tokens=*" %%i in (`"%VSWHERE_PATH%" -legacy -latest -property installationPath`) do ( - set "VSPATH="%%i\VC\Auxiliary\Build\vcvars64.bat"" + set "VSPATH="%%i\VC\Auxiliary\Build\vcvarsall.bat"" ) -call %VSPATH% +call %VSPATH% %ARCH% -rem vcvars64 sets up the MSVC headers and the Windows SDK but does not put the LLVM tools +rem vcvarsall sets up the MSVC headers and the Windows SDK but does not put the LLVM tools rem on PATH. Check up front rather than letting a missing clang-cl fail five times over rem and still fall through to the staging step with no objects to archive. -where %TSLANG_CC% >nul 2>&1 +where %TSLANG_CC_TOOL% >nul 2>&1 if errorlevel 1 ( echo "" echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - echo "XXX compiler %TSLANG_CC% is not on PATH" + echo "XXX compiler %TSLANG_CC_TOOL% is not on PATH" echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" echo "" exit /b 1 @@ -135,66 +177,74 @@ if errorlevel 1 ( rem Only now that the toolchain is known good, clear this model's output folders - rem an earlier wipe would leave them empty whenever a check above bails out. -rd /S /Q dll\%BUILD%\%MM% -rd /S /Q lib\%BUILD%\%MM% +rd /S /Q %DLL_OUT% +rd /S /Q %LIB_OUT% -md dll\%BUILD%\%MM% -md lib\%BUILD%\%MM% +md %DLL_OUT% +md %LIB_OUT% rem echo on rem Build native wrappers for C++ code -%TSLANG_CC% %DBG_CL% /EHsc /Wall /c /Fo%OUTPUT%\lib\%BUILD%\%MM%\ %SRC%\src\wrappers\io.cpp -%TSLANG_CC% %DBG_CL% /EHsc /Wall /c /Fo%OUTPUT%\lib\%BUILD%\%MM%\ %SRC%\src\wrappers\datetime.cpp -%TSLANG_CC% %DBG_CL% /EHsc /Wall /c /Fo%OUTPUT%\lib\%BUILD%\%MM%\ %SRC%\src\wrappers\regex.cpp -%TSLANG_CC% %DBG_CL% /EHsc /Wall /c /Fo%OUTPUT%\lib\%BUILD%\%MM%\ %SRC%\src\wrappers\thread.cpp -%TSLANG_CC% %DBG_CL% /EHsc /Wall /c /Fo%OUTPUT%\lib\%BUILD%\%MM%\ %SRC%\src\wrappers\http.cpp +%TSLANG_CC% %DBG_CL% /EHsc /Wall /c /Fo%OUTPUT%\%LIB_OUT%\ %SRC%\src\wrappers\io.cpp +%TSLANG_CC% %DBG_CL% /EHsc /Wall /c /Fo%OUTPUT%\%LIB_OUT%\ %SRC%\src\wrappers\datetime.cpp +%TSLANG_CC% %DBG_CL% /EHsc /Wall /c /Fo%OUTPUT%\%LIB_OUT%\ %SRC%\src\wrappers\regex.cpp +%TSLANG_CC% %DBG_CL% /EHsc /Wall /c /Fo%OUTPUT%\%LIB_OUT%\ %SRC%\src\wrappers\thread.cpp +%TSLANG_CC% %DBG_CL% /EHsc /Wall /c /Fo%OUTPUT%\%LIB_OUT%\ %SRC%\src\wrappers\http.cpp rem Build OS-specific Lib echo Build OS-specific Lib -%TOOL_PATH%\%TOOL_NAME%.exe %DBG% %MM_OPT% --emit=obj --export=none --nowarn --no-default-lib %SRC%\src\lib.win32.ts -o %OUTPUT%\lib\%BUILD%\%MM%\lib.win32.obj +%TOOL_PATH%\%TOOL_NAME%.exe %TRIPLE_OPT% %DBG% %MM_OPT% --emit=obj --export=none --nowarn --no-default-lib %SRC%\src\lib.win32.ts -o %OUTPUT%\%LIB_OUT%\lib.win32.obj rem Build DLL echo Build DLL -%TOOL_PATH%\%TOOL_NAME%.exe %DBG% %MM_OPT% --emit=dll --gc-lib-path=%GC_SHARED_LIB_PATH% --embed-declarations=false --nowarn --no-default-lib %SRC%\src\lib.ts --obj=%OUTPUT%\lib\%BUILD%\%MM%\lib.win32.obj --obj=%OUTPUT%\lib\%BUILD%\%MM%\io.obj --obj=%OUTPUT%\lib\%BUILD%\%MM%\datetime.obj --obj=%OUTPUT%\lib\%BUILD%\%MM%\regex.obj --obj=%OUTPUT%\lib\%BUILD%\%MM%\thread.obj --obj=%OUTPUT%\lib\%BUILD%\%MM%\http.obj -o %OUTPUT%\dll\%BUILD%\%MM%\TypeScriptDefaultLib.dll +%TOOL_PATH%\%TOOL_NAME%.exe %TRIPLE_OPT% %DBG% %MM_OPT% --emit=dll --gc-lib-path=%GC_SHARED_LIB_PATH% %TSLANG_RUNTIME_OPT% --embed-declarations=false --nowarn --no-default-lib %SRC%\src\lib.ts --obj=%OUTPUT%\%LIB_OUT%\lib.win32.obj --obj=%OUTPUT%\%LIB_OUT%\io.obj --obj=%OUTPUT%\%LIB_OUT%\datetime.obj --obj=%OUTPUT%\%LIB_OUT%\regex.obj --obj=%OUTPUT%\%LIB_OUT%\thread.obj --obj=%OUTPUT%\%LIB_OUT%\http.obj -o %OUTPUT%\%DLL_OUT%\TypeScriptDefaultLib.dll rem Build Lib echo Build Lib -%TOOL_PATH%\%TOOL_NAME%.exe %DBG% %MM_OPT% --emit=obj --export=none --nowarn --no-default-lib %SRC%\src\lib.ts -o %OUTPUT%\lib\%BUILD%\%MM%\lib.obj -rem %TOOL_PATH%\%TOOL_NAME%.exe %DBG% %MM_OPT% --emit=llvm --export=none %SRC%\src\lib.ts -o %OUTPUT%\lib\%BUILD%\%MM%\lib.ll -rem %TOOL_PATH%\%TOOL_NAME%.exe %DBG% %MM_OPT% --emit=mlir --export=none %SRC%\src\lib.ts 2> %OUTPUT%\lib\%BUILD%\%MM%\lib.mlir +%TOOL_PATH%\%TOOL_NAME%.exe %TRIPLE_OPT% %DBG% %MM_OPT% --emit=obj --export=none --nowarn --no-default-lib %SRC%\src\lib.ts -o %OUTPUT%\%LIB_OUT%\lib.obj +rem %TOOL_PATH%\%TOOL_NAME%.exe %TRIPLE_OPT% %DBG% %MM_OPT% --emit=llvm --export=none %SRC%\src\lib.ts -o %OUTPUT%\%LIB_OUT%\lib.ll +rem %TOOL_PATH%\%TOOL_NAME%.exe %TRIPLE_OPT% %DBG% %MM_OPT% --emit=mlir --export=none %SRC%\src\lib.ts 2> %OUTPUT%\%LIB_OUT%\lib.mlir -%TSLANG_AR% /out:%OUTPUT%\lib\%BUILD%\%MM%\TypeScriptDefaultLib.lib %OUTPUT%\lib\%BUILD%\%MM%\lib.obj %OUTPUT%\lib\%BUILD%\%MM%\lib.win32.obj %OUTPUT%\lib\%BUILD%\%MM%\io.obj %OUTPUT%\lib\%BUILD%\%MM%\datetime.obj %OUTPUT%\lib\%BUILD%\%MM%\regex.obj %OUTPUT%\lib\%BUILD%\%MM%\thread.obj %OUTPUT%\lib\%BUILD%\%MM%\http.obj +%TSLANG_AR% /out:%OUTPUT%\%LIB_OUT%\TypeScriptDefaultLib.lib %OUTPUT%\%LIB_OUT%\lib.obj %OUTPUT%\%LIB_OUT%\lib.win32.obj %OUTPUT%\%LIB_OUT%\io.obj %OUTPUT%\%LIB_OUT%\datetime.obj %OUTPUT%\%LIB_OUT%\regex.obj %OUTPUT%\%LIB_OUT%\thread.obj %OUTPUT%\%LIB_OUT%\http.obj -del %OUTPUT%\lib\%BUILD%\%MM%\lib.obj -del %OUTPUT%\lib\%BUILD%\%MM%\lib.win32.obj -del %OUTPUT%\lib\%BUILD%\%MM%\io.obj -del %OUTPUT%\lib\%BUILD%\%MM%\datetime.obj -del %OUTPUT%\lib\%BUILD%\%MM%\regex.obj -del %OUTPUT%\lib\%BUILD%\%MM%\thread.obj -del %OUTPUT%\lib\%BUILD%\%MM%\http.obj +del %OUTPUT%\%LIB_OUT%\lib.obj +del %OUTPUT%\%LIB_OUT%\lib.win32.obj +del %OUTPUT%\%LIB_OUT%\io.obj +del %OUTPUT%\%LIB_OUT%\datetime.obj +del %OUTPUT%\%LIB_OUT%\regex.obj +del %OUTPUT%\%LIB_OUT%\thread.obj +del %OUTPUT%\%LIB_OUT%\http.obj rem Stage into a single shared defaultlib tree with per-build subfolders under rem dll\ and lib\. Only the current build's subfolders are refreshed so the rem other mode (debug/release) staged by a separate run is preserved. set BUILD_LIB_PATH=.\__build\defaultlib -rd /S /Q %BUILD_LIB_PATH%\dll\%BUILD%\%MM% -rd /S /Q %BUILD_LIB_PATH%\lib\%BUILD%\%MM% -md %BUILD_LIB_PATH%\dll\%BUILD%\%MM% -md %BUILD_LIB_PATH%\lib\%BUILD%\%MM% +rd /S /Q %BUILD_LIB_PATH%\%DLL_OUT% +rd /S /Q %BUILD_LIB_PATH%\%LIB_OUT% +md %BUILD_LIB_PATH%\%DLL_OUT% +md %BUILD_LIB_PATH%\%LIB_OUT% rem Record which compiler built this library, so a mismatch (e.g. after an ABI or rem codegen change in tslang) can be diagnosed from the artifact alone. The wrapper rem toolchain is recorded too, since the MSVC and LLVM builds share one output tree. -%TOOL_PATH%\%TOOL_NAME%.exe --version > %BUILD_LIB_PATH%\COMPILER_VERSION.txt 2>&1 -echo wrappers: %TSLANG_TOOLCHAIN% (%TSLANG_CC%, %TSLANG_AR%) >> %BUILD_LIB_PATH%\COMPILER_VERSION.txt +rem BUILD_LIB_PATH (__build\defaultlib) is shared by both arch trees, so a plain +rem COMPILER_VERSION.txt would be truncated and overwritten by whichever arch built +rem last, hiding one of the two records. The x64 file name stays as it always was - +rem x64 output is otherwise byte-for-byte unchanged - and only x86 gets a second, +rem separate file alongside it. +set VERSION_FILE=COMPILER_VERSION.txt +if "%ARCH%"=="x86" set VERSION_FILE=COMPILER_VERSION.x86.txt +%TOOL_PATH%\%TOOL_NAME%.exe --version > %BUILD_LIB_PATH%\%VERSION_FILE% 2>&1 +echo wrappers: %TSLANG_TOOLCHAIN% (%TSLANG_CC%, %TSLANG_AR%) >> %BUILD_LIB_PATH%\%VERSION_FILE% +echo arch: %ARCH% >> %BUILD_LIB_PATH%\%VERSION_FILE% -xcopy %SRC%\dll\%BUILD%\%MM% %BUILD_LIB_PATH%\dll\%BUILD%\%MM% /h /i /c /k /e /r /y -xcopy %SRC%\lib\%BUILD%\%MM% %BUILD_LIB_PATH%\lib\%BUILD%\%MM% /h /i /c /k /e /r /y +xcopy %SRC%\%DLL_OUT% %BUILD_LIB_PATH%\%DLL_OUT% /h /i /c /k /e /r /y +xcopy %SRC%\%LIB_OUT% %BUILD_LIB_PATH%\%LIB_OUT% /h /i /c /k /e /r /y xcopy %SRC%\src\*.d.ts %BUILD_LIB_PATH% /h /c /k /e /r /y xcopy %SRC%\src\generics\*.ts %BUILD_LIB_PATH%\generics /h /c /k /e /r /y -if exist .\dll\%BUILD%\%MM%\TypeScriptDefaultLib.dll ( +if exist .\%DLL_OUT%\TypeScriptDefaultLib.dll ( echo "" echo "||||||||||||||||||||||||||||" echo "|||||||||| SUCCESS |||||||||" diff --git a/scripts/build_llvm.bat b/scripts/build_llvm.bat index d8b5e2f..ff4501b 100644 --- a/scripts/build_llvm.bat +++ b/scripts/build_llvm.bat @@ -4,10 +4,14 @@ @rem scripts\build_llvm.bat debug gc @rem @rem clang-cl still compiles against the MSVC headers and the Windows SDK, which -@rem build_core.bat sets up via vcvars64. vcvars64 does not add the LLVM tools to PATH, +@rem build_core.bat sets up via vcvarsall. vcvarsall does not add the LLVM tools to PATH, @rem so clang-cl and llvm-lib must already be there - a default LLVM install puts them @rem in %ProgramFiles%\LLVM\bin. build_core.bat checks for both before compiling. @rem +@rem clang-cl targets x64 regardless of which vcvarsall was called, so under +@rem TSLANG_ARCH=x86 build_core.bat appends -m32 to TSLANG_CC itself; nothing to do here. +@rem llvm-lib infers its output machine from its input objects, so it needs no flag either. +@rem @rem The build body lives in build_core.bat and is shared with build_vs.bat, so a @rem change to flags or layout reaches both toolchains. diff --git a/src/lib.ts b/src/lib.ts index 12095ee..40e7e6f 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -589,7 +589,7 @@ export class RegExp } replaceAll(s: string, replacement: string): string { - const r = regexp_replace(this.source, this.flags, s); + const r = regexp_replace(this.source, this.flags, s, replacement); const len = r.length; let result = "".clone().resize(len); memcpy(Ref(result[0]), r, len); diff --git a/tests.ps1 b/tests.ps1 index 55026a9..d5da5bb 100644 --- a/tests.ps1 +++ b/tests.ps1 @@ -50,8 +50,36 @@ function Test([string]$config, [string]$mode, [string]$fileName) $DBG_ARGS = [string[]]$(if ($DBG -ne "") { $DBG -split " " } else { @() }) $OPTIONS_ARGS = [string[]]$(if ($OPTIONS -ne "") { $OPTIONS -split " " } else { @() }) + $isX86 = ($Env:TSLANG_ARCH -eq "x86") + + if ($isX86) { + # x86 mode hardcodes the sibling ..\TypeScriptCompiler layout for GC_LIB_PATH_X86 and + # TSLANG_LIB_PATH_X86 below, unlike the x64 path above: it ignores $Env:TOOL_PATH (and + # the $BUILD_PATH/$TOOL_PATH it would otherwise redirect) entirely, so a custom TOOL_PATH + # has no effect on which x86 gc/runtime libraries a x86 test run links against. + # 32-bit exes link statically; --shared-libs=...TypeScriptRuntime.dll below is an x64 + # JIT-only DLL (tslang.cpp's clSharedLibs, read only by --emit=jit in jit.cpp) that + # --emit=exe never consumes, so it is dropped here rather than passed and ignored. + # --gc-lib-path/--tslang-lib-path/--default-lib-path are passed explicitly (not left to + # the $Env: defaults set above) so a value already sitting in the environment for this + # session can't leak into the x86 build; the compiler appends "x86" to the first two + # itself, and computes the x86 default-lib subdirectory under the same base path used + # for x64 (see getDefaultLibSubDir). --default-lib-path here is deliberate isolation, + # not a behavior change: it is the same $DEFAULTLIB_BUILD_PATH the $Env:DEFAULT_LIB_PATH + # default above already carries, so this only stops that env var (guarded by the + # `$Env:DEFAULT_LIB_PAT` typo elsewhere in this function, never fixed here) from being + # the sole thing standing between an x86 run and a stale x64 value. + $GC_LIB_PATH_X86="..\TypeScriptCompiler\3rdParty\gc\x64\$BUILD\lib" + $TSLANG_LIB_PATH_X86="..\TypeScriptCompiler\__build\tslang-runtime\$BUILD" + $ARCH_ARGS = @("-mtriple=i686-pc-windows-msvc", "--gc-lib-path=$GC_LIB_PATH_X86", "--tslang-lib-path=$TSLANG_LIB_PATH_X86", "--default-lib-path=$DEFAULTLIB_BUILD_PATH") + } + if ($mode -eq "compile") { - $compile_error_output = ($compile_output = & $TOOL_PATH\$TOOL.exe @DBG_ARGS @OPTIONS_ARGS --shared-libs=$TOOL_PATH\TypeScriptRuntime.dll --emit=exe $SRC\tests\$test.ts) 2>&1 + if ($isX86) { + $compile_error_output = ($compile_output = & $TOOL_PATH\$TOOL.exe @DBG_ARGS @OPTIONS_ARGS @ARCH_ARGS --emit=exe $SRC\tests\$test.ts) 2>&1 + } else { + $compile_error_output = ($compile_output = & $TOOL_PATH\$TOOL.exe @DBG_ARGS @OPTIONS_ARGS --shared-libs=$TOOL_PATH\TypeScriptRuntime.dll --emit=exe $SRC\tests\$test.ts) 2>&1 + } $compile_code = $LASTEXITCODE @@ -126,10 +154,17 @@ function Tests([string]$config, [string]$mode) $allFailedTests = @() -$allFailedTests += Tests "release" "compile" | ForEach-Object { "release/compile: $_" } -$allFailedTests += Tests "release" "jit" | ForEach-Object { "release/jit: $_" } -$allFailedTests += Tests "debug" "compile" | ForEach-Object { "debug/compile: $_" } -$allFailedTests += Tests "debug" "jit" | ForEach-Object { "debug/jit: $_" } +if ($Env:TSLANG_ARCH -eq "x86") { + # The JIT (jit.cpp) refuses x86 targets by design; only the two compile passes apply. + Write-Host "jit is host-only; skipped for x86" -ForegroundColor Yellow + $allFailedTests += Tests "release" "compile" | ForEach-Object { "release/compile: $_" } + $allFailedTests += Tests "debug" "compile" | ForEach-Object { "debug/compile: $_" } +} else { + $allFailedTests += Tests "release" "compile" | ForEach-Object { "release/compile: $_" } + $allFailedTests += Tests "release" "jit" | ForEach-Object { "release/jit: $_" } + $allFailedTests += Tests "debug" "compile" | ForEach-Object { "debug/compile: $_" } + $allFailedTests += Tests "debug" "jit" | ForEach-Object { "debug/jit: $_" } +} if ($allFailedTests.Count -gt 0) { Write-Host "Done. $($allFailedTests.Count) test(s) failed:" -ForegroundColor Red