Skip to content

Commit 0a01e76

Browse files
Binaries staged per target triple; Android shares the one defaultlib tree (#30)
* Binaries staged per target triple; Android shares the one defaultlib tree __build/defaultlib/{lib,dll}/<arch>/<vendor>/<os>/<env>/{debug,release}/{gc,rc,none}/ for every target: x64 Windows is x86_64/pc/windows/msvc, x86 i386/pc/windows/msvc, Linux x86_64/unknown/linux/gnu, Android <aarch64|x86_64>/unknown/linux/android. The scripts ask tslang --print-default-lib-dir (TypeScriptCompiler, same PR series) for each folder with the flags they compile with, so they stage exactly where tslang later looks. The declarations stay at the defaultlib root, shared by every build: build_android.bat stages into __build/defaultlib rather than __build/android/<abi>, and a program takes --default-lib-path=__build whatever its target. build.bat: a failed single-model build (build.bat <mode> <model>) returned 0, since %errorlevel% inside a ( ) block is expanded before the build runs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: add __build.pre-triple to .gitignore to prevent unnecessary file tracking --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent aece64a commit 0a01e76

8 files changed

Lines changed: 141 additions & 75 deletions

File tree

‎.gitignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/dll
22
/lib
3+
/defaultlib
34
/__build
5+
/__build.pre-triple
46
/node_modules
57
/tsconfig.json
68
*.exe

‎README.md‎

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@ build.bat # x64, release and debug, all three memory models
88
build.bat release gc # x64, just that one
99
```
1010

11+
Every build stages into one tree, `__build\defaultlib`, which a program takes with
12+
`--default-lib-path=__build`. The binaries are split by target, as its LLVM triple names it
13+
(arch, vendor, OS, environment), then by build mode, then by memory model:
14+
15+
```
16+
__build\defaultlib\{lib,dll}\<arch>\<vendor>\<os>\<env>\<debug|release>\<gc|rc|none>\
17+
e.g. lib\x86_64\pc\windows\msvc\release\gc\TypeScriptDefaultLib.lib
18+
lib\aarch64\unknown\linux\android\release\gc\libTypeScriptDefaultLib.a
19+
__build\defaultlib\*.d.ts, generics\ ... (the declarations, shared by every build)
20+
```
21+
22+
The scripts do not spell these folders out: they ask the compiler, which looks the library up
23+
the same way (`tslang --print-default-lib-dir=<lib|dll> [-mtriple=...] [--di] -mm=<model>`).
24+
1125
For 32-bit Windows, set `TSLANG_ARCH=x86` before calling `build.bat` (it is an
1226
environment variable, not a positional argument, the same idiom as `TSLANG_TOOLCHAIN`):
1327

@@ -21,8 +35,8 @@ PowerShell) - since it is a session-wide environment variable, not a
2135
one-shot argument: a later plain `build.bat` or `tslang --install-default-lib`
2236
run in the same shell would otherwise silently build only the x86 tree.
2337

24-
This stages into `__build\defaultlib\{lib,dll}\x86\<debug|release>\<gc|rc|none>\`,
25-
alongside the existing x64 tree. It requires two things already built in the compiler
38+
This stages into `__build\defaultlib\{lib,dll}\i386\pc\windows\msvc\<debug|release>\<gc|rc|none>\`,
39+
alongside the x64 tree. It requires two things already built in the compiler
2640
repo:
2741

2842
- the x86 Boehm GC: `prepare_3rdParty.bat <debug|release> x86` in `TypeScriptCompiler`;
@@ -39,9 +53,9 @@ scripts\build_android.bat # arm64-v8a and x86_64, release
3953
scripts\build_android.bat arm64-v8a release gc # just that one
4054
```
4155

42-
This builds for API level 29 (the lowest with `timespec_get`) into
43-
`__build\android\<abi>\defaultlib\lib\<debug|release>\<gc|rc|none>\`, one complete tree
44-
per ABI. It needs a `tslang.exe` that can target Android (`TOOL_PATH`, default: the compiler's
56+
This builds for API level 29 (the lowest with `timespec_get`) into the same tree as every
57+
other target: `__build\defaultlib\lib\<aarch64|x86_64>\unknown\linux\android\<debug|release>\<gc|rc|none>\`.
58+
It needs a `tslang.exe` that can target Android (`TOOL_PATH`, default: the compiler's
4559
release build tree). Android has no libcurl, so HTTP is `src\wrappers\http_stub.cpp`: `fetch()`
4660
throws. Only the static library is built: tslang links it into every Android binary.
4761

@@ -52,7 +66,7 @@ arm64-v8a under `gc`, a shared library an app loads, or an executable:
5266

5367
```
5468
tslang --emit=dll -mtriple=aarch64-linux-android29 --opt -mm=gc ^
55-
--default-lib-path=__build\android\arm64-v8a ^
69+
--default-lib-path=__build ^
5670
--gc-lib-path=<TypeScriptCompiler>\3rdParty\gc\android\arm64-v8a\release\lib ^
5771
--tslang-lib-path=<TypeScriptCompiler>\__build\tslang-runtime\release\android\arm64-v8a ^
5872
mylib.ts -o libmylib.so
@@ -62,11 +76,12 @@ tslang --emit=dll -mtriple=aarch64-linux-android29 --opt -mm=gc ^
6276
static default library, collector and libc++ are linked in, so it needs only Bionic's libc, libm
6377
and libdl. The triple has to carry the API level (`...-android29`).
6478

65-
The Windows release zip carries all of this prebuilt, per ABI (`arm64-v8a`, `x86_64`): the
66-
default library in every mode and model, the collector and async runtime as release builds:
79+
The Windows release zip carries all of this prebuilt for both ABIs (`arm64-v8a`, `x86_64`): the
80+
default library in every mode and model, in its `defaultlib` tree beside the Windows one, and the
81+
collector and async runtime as release builds:
6782

6883
```
69-
android\<abi>\defaultlib\... --default-lib-path=<zip>\android\<abi>
84+
defaultlib\... --default-lib-path=<zip>
7085
android\<abi>\lib\libgc.a --gc-lib-path=<zip>\android\<abi>\lib
7186
android\<abi>\lib\libTypeScriptAsyncRuntime.a --tslang-lib-path=<zip>\android\<abi>\lib
7287
```

‎build.bat‎

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,30 @@
1313
@rem set TSLANG_ARCH=x86
1414
@rem build.bat release gc
1515
@rem Like TSLANG_TOOLCHAIN, it is an environment variable, not a positional argument -
16-
@rem %1/%2 stay "mode model" either way. x86 stages into lib\x86\... and dll\x86\...,
17-
@rem alongside the x64 tree, and needs the x86 Boehm GC prerequisite (see README.md).
16+
@rem %1/%2 stay "mode model" either way. x86 stages into lib\i386\pc\windows\msvc\... and
17+
@rem dll\i386\..., alongside the x64 tree (lib\x86_64\pc\windows\msvc\...), and needs the x86
18+
@rem Boehm GC prerequisite (see README.md).
1819
@rem
1920
@rem Set TSLANG_DEBUG_CRT=/MT to build the debug archive against the release C runtime, for a
2021
@rem package whose runtime/collector/LLVM libraries are all release builds (the compiler's
2122
@rem release zip). The default, /MTd, matches a debug tslang build. See scripts\build_core.bat.
2223
@rem
23-
@rem See tslang/include/TypeScript/Defines.h for the resulting layout.
24+
@rem See tslang/include/TypeScript/Defines.h for the resulting layout:
25+
@rem __build\defaultlib\{lib,dll}\<arch>\<vendor>\<os>\<env>\{debug,release}\{gc,rc,none}, as
26+
@rem tslang --print-default-lib-dir names each folder, and the declarations at the defaultlib root.
2427

2528
if /I "%TSLANG_TOOLCHAIN%" == "llvm" (
2629
set "BUILD_SCRIPT=scripts\build_llvm.bat"
2730
) else (
2831
set "BUILD_SCRIPT=scripts\build_vs.bat"
2932
)
3033

31-
if not "%2" == "" (
32-
cmd /c %BUILD_SCRIPT% %1 %2
33-
exit /b %errorlevel%
34-
)
34+
rem Not inside a ( ) block: there %errorlevel% is expanded when the block is read, before the
35+
rem build runs, so a failed single-model build returned 0.
36+
if "%2" == "" goto all_models
37+
cmd /c %BUILD_SCRIPT% %1 %2
38+
exit /b %errorlevel%
39+
:all_models
3540

3641
if "%1" == "debug" (
3742
call :build_all_models debug

‎scripts/build.sh‎

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -62,28 +62,39 @@ if [ -z "${TSLANG_LIB_PATH}" ]; then
6262
export TSLANG_LIB_PATH=$BUILD_PATH/$TOOL_NAME/ninja/$BUILD/lib
6363
fi
6464

65-
rm -rf dll/$BUILD/$MM lib/$BUILD/$MM
66-
mkdir -p dll/$BUILD/$MM
67-
mkdir -p lib/$BUILD/$MM
68-
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/io.cpp -o $OUTPUT/lib/$BUILD/$MM/io.o
69-
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/datetime.cpp -o $OUTPUT/lib/$BUILD/$MM/datetime.o
70-
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/regex.cpp -o $OUTPUT/lib/$BUILD/$MM/regex.o
71-
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/thread.cpp -o $OUTPUT/lib/$BUILD/$MM/thread.o
72-
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/http_linux.cpp -o $OUTPUT/lib/$BUILD/$MM/http_linux.o
73-
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/memory.cpp -o $OUTPUT/lib/$BUILD/$MM/memory.o
74-
75-
$BIN_PATH/$TOOL_NAME $DBG_OPTS $MM_OPT --emit=obj --export=none --nowarn --no-default-lib $SRC/src/lib.linux.ts $PIC -o $OUTPUT/lib/$BUILD/$MM/lib.linux.o
65+
# The output folders, from tslang itself (--print-default-lib-dir), with the same build and model
66+
# flags it compiles with below: defaultlib/{lib,dll}/<arch>/<vendor>/<os>/<env>/<build>/<model>, composed
67+
# the way tslang later looks the library up (see tslang/include/TypeScript/Defines.h). Spelled out
68+
# here, the two would drift apart.
69+
LIB_OUT=$($BIN_PATH/$TOOL_NAME --print-default-lib-dir=lib $DBG_OPTS $MM_OPT)
70+
DLL_OUT=$($BIN_PATH/$TOOL_NAME --print-default-lib-dir=dll $DBG_OPTS $MM_OPT)
71+
if [ -z "$LIB_OUT" ] || [ -z "$DLL_OUT" ] ; then
72+
echo "$BIN_PATH/$TOOL_NAME cannot name the output folders (--print-default-lib-dir): it predates the per-target layout, or is missing"
73+
exit 1
74+
fi
75+
76+
rm -rf $DLL_OUT $LIB_OUT
77+
mkdir -p $DLL_OUT
78+
mkdir -p $LIB_OUT
79+
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/io.cpp -o $OUTPUT/$LIB_OUT/io.o
80+
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/datetime.cpp -o $OUTPUT/$LIB_OUT/datetime.o
81+
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/regex.cpp -o $OUTPUT/$LIB_OUT/regex.o
82+
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/thread.cpp -o $OUTPUT/$LIB_OUT/thread.o
83+
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/http_linux.cpp -o $OUTPUT/$LIB_OUT/http_linux.o
84+
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/memory.cpp -o $OUTPUT/$LIB_OUT/memory.o
85+
86+
$BIN_PATH/$TOOL_NAME $DBG_OPTS $MM_OPT --emit=obj --export=none --nowarn --no-default-lib $SRC/src/lib.linux.ts $PIC -o $OUTPUT/$LIB_OUT/lib.linux.o
7687

7788
# Build Lib
78-
$BIN_PATH/$TOOL_NAME $DBG_OPTS $MM_OPT --emit=obj --export=none --nowarn --no-default-lib $SRC/src/lib.ts $PIC -o $OUTPUT/lib/$BUILD/$MM/lib.o
79-
$ARC rcs $OUTPUT/lib/$BUILD/$MM/libTypeScriptDefaultLibCore.a $OUTPUT/lib/$BUILD/$MM/lib.o $OUTPUT/lib/$BUILD/$MM/lib.linux.o $OUTPUT/lib/$BUILD/$MM/io.o $OUTPUT/lib/$BUILD/$MM/datetime.o $OUTPUT/lib/$BUILD/$MM/regex.o $OUTPUT/lib/$BUILD/$MM/thread.o $OUTPUT/lib/$BUILD/$MM/http_linux.o $OUTPUT/lib/$BUILD/$MM/memory.o
89+
$BIN_PATH/$TOOL_NAME $DBG_OPTS $MM_OPT --emit=obj --export=none --nowarn --no-default-lib $SRC/src/lib.ts $PIC -o $OUTPUT/$LIB_OUT/lib.o
90+
$ARC rcs $OUTPUT/$LIB_OUT/libTypeScriptDefaultLibCore.a $OUTPUT/$LIB_OUT/lib.o $OUTPUT/$LIB_OUT/lib.linux.o $OUTPUT/$LIB_OUT/io.o $OUTPUT/$LIB_OUT/datetime.o $OUTPUT/$LIB_OUT/regex.o $OUTPUT/$LIB_OUT/thread.o $OUTPUT/$LIB_OUT/http_linux.o $OUTPUT/$LIB_OUT/memory.o
8091

8192
# A static archive cannot record its own dependencies on ELF (there is no ld.bfd equivalent of
8293
# the `#pragma comment(lib, ...)` http.cpp uses on Windows), so programs linking
8394
# -lTypeScriptDefaultLib failed with undefined curl_* references. libTypeScriptDefaultLib.a is
8495
# therefore a GNU linker script (as glibc's libc.so is) that pulls in the real archive plus the
8596
# system libraries it needs. The compiler keeps passing -lTypeScriptDefaultLib unchanged.
86-
cat > $OUTPUT/lib/$BUILD/$MM/libTypeScriptDefaultLib.a <<EOF
97+
cat > $OUTPUT/$LIB_OUT/libTypeScriptDefaultLib.a <<EOF
8798
/* GNU ld script: TypeScriptDefaultLib and its external dependencies */
8899
INPUT(-lTypeScriptDefaultLibCore -lcurl)
89100
EOF
@@ -94,26 +105,28 @@ EOF
94105
# undefined on purpose: they must bind to the one collector already in the process
95106
# (libTypeScriptRuntime.so under the JIT, libgc.a in an exe); linking libgc.a in here would
96107
# give the library a second, separate heap.
97-
g++ -shared $DBG_GCC $OUTPUT/lib/$BUILD/$MM/lib.o $OUTPUT/lib/$BUILD/$MM/lib.linux.o $OUTPUT/lib/$BUILD/$MM/io.o $OUTPUT/lib/$BUILD/$MM/datetime.o $OUTPUT/lib/$BUILD/$MM/regex.o $OUTPUT/lib/$BUILD/$MM/thread.o $OUTPUT/lib/$BUILD/$MM/http_linux.o $OUTPUT/lib/$BUILD/$MM/memory.o -lcurl -lm -o $OUTPUT/dll/$BUILD/$MM/libTypeScriptDefaultLib.so
108+
g++ -shared $DBG_GCC $OUTPUT/$LIB_OUT/lib.o $OUTPUT/$LIB_OUT/lib.linux.o $OUTPUT/$LIB_OUT/io.o $OUTPUT/$LIB_OUT/datetime.o $OUTPUT/$LIB_OUT/regex.o $OUTPUT/$LIB_OUT/thread.o $OUTPUT/$LIB_OUT/http_linux.o $OUTPUT/$LIB_OUT/memory.o -lcurl -lm -o $OUTPUT/$DLL_OUT/libTypeScriptDefaultLib.so
98109

99110
# Copy
100-
# Stage into a single shared defaultlib tree with per-build subfolders under dll/ and lib/,
101-
# each holding one subfolder per memory model. Only the current build's subfolders are
102-
# refreshed, and they are refreshed from the source tree, so the other mode (debug/release)
103-
# staged by a separate run is preserved and so are the models staged by earlier runs of this
104-
# one - only this run's model was removed from the source tree above.
105-
BUILD_LIB_PATH=./__build/defaultlib/
106-
rm -rf $BUILD_LIB_PATH/dll/$BUILD/$MM $BUILD_LIB_PATH/lib/$BUILD/$MM
107-
mkdir -p $BUILD_LIB_PATH/dll/$BUILD/$MM
108-
mkdir -p $BUILD_LIB_PATH/lib/$BUILD/$MM
111+
# Stage into a single shared defaultlib tree with per-target, per-build and per-model subfolders
112+
# under dll/ and lib/. Only the current build's subfolders are refreshed, and they are refreshed
113+
# from the source tree, so the other targets and modes (debug/release) staged by separate runs are
114+
# preserved and so are the models staged by earlier runs of this one - only this run's model was
115+
# removed from the source tree above. LIB_OUT/DLL_OUT start with defaultlib/, so they go under
116+
# STAGE_PATH; the declarations go to its defaultlib/ root, shared by every build.
117+
STAGE_PATH=./__build
118+
BUILD_LIB_PATH=$STAGE_PATH/defaultlib/
119+
rm -rf $STAGE_PATH/$DLL_OUT $STAGE_PATH/$LIB_OUT
120+
mkdir -p $STAGE_PATH/$DLL_OUT
121+
mkdir -p $STAGE_PATH/$LIB_OUT
109122

110123
# Record which compiler built this library, so a mismatch (e.g. after an ABI or
111124
# codegen change in tslang) can be diagnosed from the artifact alone.
112125
$BIN_PATH/$TOOL_NAME --version > $BUILD_LIB_PATH/COMPILER_VERSION.txt 2>&1
113126

114127
# cleanup intermediate object files
115-
rm $OUTPUT/lib/$BUILD/$MM/*.o
128+
rm $OUTPUT/$LIB_OUT/*.o
116129

117-
cp -r $SRC/dll/$BUILD/$MM/* $BUILD_LIB_PATH/dll/$BUILD/$MM/
118-
cp -r $SRC/lib/$BUILD/$MM/* $BUILD_LIB_PATH/lib/$BUILD/$MM/
130+
cp -r $SRC/$DLL_OUT/* $STAGE_PATH/$DLL_OUT/
131+
cp -r $SRC/$LIB_OUT/* $STAGE_PATH/$LIB_OUT/
119132
cp -r $SRC/src/* $BUILD_LIB_PATH

‎scripts/build_android.bat‎

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@
1212
@rem TOOL_PATH the directory holding a tslang.exe with Android support (#506); defaults
1313
@rem to the compiler's release build tree next to this repository
1414
@rem
15-
@rem Output, one complete default-library tree per ABI (a program compiled for that ABI takes
16-
@rem --default-lib-path=__build\android\<abi>, the directory holding defaultlib\):
17-
@rem __build\android\<abi>\defaultlib\lib\<mode>\<model>\libTypeScriptDefaultLib.a
18-
@rem __build\android\<abi>\defaultlib\*.d.ts ...
15+
@rem Output, into the one default-library tree every target shares (a program compiled for Android
16+
@rem takes --default-lib-path=__build, the directory holding defaultlib\, as any other does):
17+
@rem __build\defaultlib\lib\<arch>\unknown\linux\android\<mode>\<model>\libTypeScriptDefaultLib.a
18+
@rem (arch: aarch64 for arm64-v8a, x86_64 for x86_64; tslang --print-default-lib-dir names it)
19+
@rem __build\defaultlib\*.d.ts ... (shared by every target)
1920
@rem
2021
@rem Differences from build.sh:
2122
@rem - HTTP is src\wrappers\http_stub.cpp, not http_linux.cpp: libcurl is not part of Android, so
@@ -93,9 +94,19 @@ set CXX="%NDK_BIN%\clang++.exe" --target=%TRIPLE% -fPIC -std=c++17 %DBG_CXX%
9394
set AR="%NDK_BIN%\llvm-ar.exe"
9495
set TSC=%TSLANG% -mtriple=%TRIPLE% -relocation-model=pic %DBG% -mm=%MM% --emit=obj --export=none --nowarn --no-default-lib
9596

96-
set OUT=%ROOT%\__build\android\%ABI%\defaultlib
97-
set OBJ=%ROOT%\__build\android\%ABI%\obj-%MODE%-%MM%
98-
set LIB_OUT=%OUT%\lib\%MODE%\%MM%
97+
rem The archive's folder, from tslang itself with the flags it compiles with below, composed the
98+
rem way tslang later looks it up (see tslang/include/TypeScript/Defines.h).
99+
set LIB_DIR=
100+
for /f "usebackq delims=" %%d in (`"%TOOL_PATH%\tslang.exe" --print-default-lib-dir=lib -mtriple=%TRIPLE% %DBG% -mm=%MM%`) do set "LIB_DIR=%%d"
101+
if "%LIB_DIR%"=="" (
102+
echo %TSLANG% cannot name the output folder ^(--print-default-lib-dir^): it predates the per-target layout
103+
exit /b 1
104+
)
105+
set "LIB_DIR=%LIB_DIR:/=\%"
106+
107+
set OUT=%ROOT%\__build\defaultlib
108+
set OBJ=%ROOT%\__build\obj-android-%ABI%-%MODE%-%MM%
109+
set LIB_OUT=%ROOT%\__build\%LIB_DIR%
99110

100111
echo === %ABI% %MODE% %MM%
101112
if exist "%OBJ%" rd /s /q "%OBJ%"
@@ -114,7 +125,8 @@ set OBJS="%OBJ%\lib.o" "%OBJ%\lib.linux.o" "%OBJ%\io.o" "%OBJ%\datetime.o" "%OBJ
114125

115126
rd /s /q "%OBJ%"
116127

117-
rem the declarations a program compiled against this tree reads, and which compiler built it
128+
rem the declarations a program compiled against this tree reads (the same for every target), and
129+
rem which compiler built this ABI's archives, beside the other targets' records
118130
xcopy /E /I /Y /Q "%ROOT%\src" "%OUT%" > nul || exit /b 1
119-
%TSLANG% --version > "%OUT%\COMPILER_VERSION.txt" 2>&1
131+
%TSLANG% --version > "%OUT%\COMPILER_VERSION.android-%ABI%.txt" 2>&1
120132
exit /b 0

0 commit comments

Comments
 (0)