Skip to content
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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/dll
/lib
/defaultlib
/__build
/__build.pre-triple
/node_modules
/tsconfig.json
*.exe
Expand Down
33 changes: 24 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ build.bat # x64, release and debug, all three memory models
build.bat release gc # x64, just that one
```

Every build stages into one tree, `__build\defaultlib`, which a program takes with
`--default-lib-path=__build`. The binaries are split by target, as its LLVM triple names it
(arch, vendor, OS, environment), then by build mode, then by memory model:

```
__build\defaultlib\{lib,dll}\<arch>\<vendor>\<os>\<env>\<debug|release>\<gc|rc|none>\
e.g. lib\x86_64\pc\windows\msvc\release\gc\TypeScriptDefaultLib.lib
lib\aarch64\unknown\linux\android\release\gc\libTypeScriptDefaultLib.a
__build\defaultlib\*.d.ts, generics\ ... (the declarations, shared by every build)
```

The scripts do not spell these folders out: they ask the compiler, which looks the library up
the same way (`tslang --print-default-lib-dir=<lib|dll> [-mtriple=...] [--di] -mm=<model>`).

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`):

Expand All @@ -21,8 +35,8 @@ 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\<debug|release>\<gc|rc|none>\`,
alongside the existing x64 tree. It requires two things already built in the compiler
This stages into `__build\defaultlib\{lib,dll}\i386\pc\windows\msvc\<debug|release>\<gc|rc|none>\`,
alongside the x64 tree. It requires two things already built in the compiler
repo:

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

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

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

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

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

```
android\<abi>\defaultlib\... --default-lib-path=<zip>\android\<abi>
defaultlib\... --default-lib-path=<zip>
android\<abi>\lib\libgc.a --gc-lib-path=<zip>\android\<abi>\lib
android\<abi>\lib\libTypeScriptAsyncRuntime.a --tslang-lib-path=<zip>\android\<abi>\lib
```
Expand Down
19 changes: 12 additions & 7 deletions build.bat
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,30 @@
@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 %1/%2 stay "mode model" either way. x86 stages into lib\i386\pc\windows\msvc\... and
@rem dll\i386\..., alongside the x64 tree (lib\x86_64\pc\windows\msvc\...), and needs the x86
@rem Boehm GC prerequisite (see README.md).
@rem
@rem Set TSLANG_DEBUG_CRT=/MT to build the debug archive against the release C runtime, for a
@rem package whose runtime/collector/LLVM libraries are all release builds (the compiler's
@rem release zip). The default, /MTd, matches a debug tslang build. See scripts\build_core.bat.
@rem
@rem See tslang/include/TypeScript/Defines.h for the resulting layout.
@rem See tslang/include/TypeScript/Defines.h for the resulting layout:
@rem __build\defaultlib\{lib,dll}\<arch>\<vendor>\<os>\<env>\{debug,release}\{gc,rc,none}, as
@rem tslang --print-default-lib-dir names each folder, and the declarations at the defaultlib root.

if /I "%TSLANG_TOOLCHAIN%" == "llvm" (
set "BUILD_SCRIPT=scripts\build_llvm.bat"
) else (
set "BUILD_SCRIPT=scripts\build_vs.bat"
)

if not "%2" == "" (
cmd /c %BUILD_SCRIPT% %1 %2
exit /b %errorlevel%
)
rem Not inside a ( ) block: there %errorlevel% is expanded when the block is read, before the
rem build runs, so a failed single-model build returned 0.
if "%2" == "" goto all_models
cmd /c %BUILD_SCRIPT% %1 %2
exit /b %errorlevel%
:all_models

if "%1" == "debug" (
call :build_all_models debug
Expand Down
67 changes: 40 additions & 27 deletions scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,28 +62,39 @@ if [ -z "${TSLANG_LIB_PATH}" ]; then
export TSLANG_LIB_PATH=$BUILD_PATH/$TOOL_NAME/ninja/$BUILD/lib
fi

rm -rf dll/$BUILD/$MM lib/$BUILD/$MM
mkdir -p dll/$BUILD/$MM
mkdir -p lib/$BUILD/$MM
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/io.cpp -o $OUTPUT/lib/$BUILD/$MM/io.o
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/datetime.cpp -o $OUTPUT/lib/$BUILD/$MM/datetime.o
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/regex.cpp -o $OUTPUT/lib/$BUILD/$MM/regex.o
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/thread.cpp -o $OUTPUT/lib/$BUILD/$MM/thread.o
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/http_linux.cpp -o $OUTPUT/lib/$BUILD/$MM/http_linux.o
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/memory.cpp -o $OUTPUT/lib/$BUILD/$MM/memory.o

$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
# The output folders, from tslang itself (--print-default-lib-dir), with the same build and model
# flags it compiles with below: defaultlib/{lib,dll}/<arch>/<vendor>/<os>/<env>/<build>/<model>, composed
# the way tslang later looks the library up (see tslang/include/TypeScript/Defines.h). Spelled out
# here, the two would drift apart.
LIB_OUT=$($BIN_PATH/$TOOL_NAME --print-default-lib-dir=lib $DBG_OPTS $MM_OPT)
DLL_OUT=$($BIN_PATH/$TOOL_NAME --print-default-lib-dir=dll $DBG_OPTS $MM_OPT)
if [ -z "$LIB_OUT" ] || [ -z "$DLL_OUT" ] ; then
echo "$BIN_PATH/$TOOL_NAME cannot name the output folders (--print-default-lib-dir): it predates the per-target layout, or is missing"
exit 1
fi

rm -rf $DLL_OUT $LIB_OUT
mkdir -p $DLL_OUT
mkdir -p $LIB_OUT
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/io.cpp -o $OUTPUT/$LIB_OUT/io.o
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/datetime.cpp -o $OUTPUT/$LIB_OUT/datetime.o
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/regex.cpp -o $OUTPUT/$LIB_OUT/regex.o
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/thread.cpp -o $OUTPUT/$LIB_OUT/thread.o
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/http_linux.cpp -o $OUTPUT/$LIB_OUT/http_linux.o
$TOOL $DBG_GCC $CPP_FLAGS -c $SRC/src/wrappers/memory.cpp -o $OUTPUT/$LIB_OUT/memory.o

$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

# Build Lib
$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
$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
$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
$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

# A static archive cannot record its own dependencies on ELF (there is no ld.bfd equivalent of
# the `#pragma comment(lib, ...)` http.cpp uses on Windows), so programs linking
# -lTypeScriptDefaultLib failed with undefined curl_* references. libTypeScriptDefaultLib.a is
# therefore a GNU linker script (as glibc's libc.so is) that pulls in the real archive plus the
# system libraries it needs. The compiler keeps passing -lTypeScriptDefaultLib unchanged.
cat > $OUTPUT/lib/$BUILD/$MM/libTypeScriptDefaultLib.a <<EOF
cat > $OUTPUT/$LIB_OUT/libTypeScriptDefaultLib.a <<EOF
/* GNU ld script: TypeScriptDefaultLib and its external dependencies */
INPUT(-lTypeScriptDefaultLibCore -lcurl)
EOF
Expand All @@ -94,26 +105,28 @@ EOF
# undefined on purpose: they must bind to the one collector already in the process
# (libTypeScriptRuntime.so under the JIT, libgc.a in an exe); linking libgc.a in here would
# give the library a second, separate heap.
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
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

# Copy
# Stage into a single shared defaultlib tree with per-build subfolders under dll/ and lib/,
# each holding one subfolder per memory model. Only the current build's subfolders are
# refreshed, and they are refreshed from the source tree, so the other mode (debug/release)
# staged by a separate run is preserved and so are the models staged by earlier runs of this
# one - only this run's model was removed from the source tree above.
BUILD_LIB_PATH=./__build/defaultlib/
rm -rf $BUILD_LIB_PATH/dll/$BUILD/$MM $BUILD_LIB_PATH/lib/$BUILD/$MM
mkdir -p $BUILD_LIB_PATH/dll/$BUILD/$MM
mkdir -p $BUILD_LIB_PATH/lib/$BUILD/$MM
# Stage into a single shared defaultlib tree with per-target, per-build and per-model subfolders
# under dll/ and lib/. Only the current build's subfolders are refreshed, and they are refreshed
# from the source tree, so the other targets and modes (debug/release) staged by separate runs are
# preserved and so are the models staged by earlier runs of this one - only this run's model was
# removed from the source tree above. LIB_OUT/DLL_OUT start with defaultlib/, so they go under
# STAGE_PATH; the declarations go to its defaultlib/ root, shared by every build.
STAGE_PATH=./__build
BUILD_LIB_PATH=$STAGE_PATH/defaultlib/
rm -rf $STAGE_PATH/$DLL_OUT $STAGE_PATH/$LIB_OUT
mkdir -p $STAGE_PATH/$DLL_OUT
mkdir -p $STAGE_PATH/$LIB_OUT

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

# cleanup intermediate object files
rm $OUTPUT/lib/$BUILD/$MM/*.o
rm $OUTPUT/$LIB_OUT/*.o

cp -r $SRC/dll/$BUILD/$MM/* $BUILD_LIB_PATH/dll/$BUILD/$MM/
cp -r $SRC/lib/$BUILD/$MM/* $BUILD_LIB_PATH/lib/$BUILD/$MM/
cp -r $SRC/$DLL_OUT/* $STAGE_PATH/$DLL_OUT/
cp -r $SRC/$LIB_OUT/* $STAGE_PATH/$LIB_OUT/
cp -r $SRC/src/* $BUILD_LIB_PATH
30 changes: 21 additions & 9 deletions scripts/build_android.bat
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
@rem TOOL_PATH the directory holding a tslang.exe with Android support (#506); defaults
@rem to the compiler's release build tree next to this repository
@rem
@rem Output, one complete default-library tree per ABI (a program compiled for that ABI takes
@rem --default-lib-path=__build\android\<abi>, the directory holding defaultlib\):
@rem __build\android\<abi>\defaultlib\lib\<mode>\<model>\libTypeScriptDefaultLib.a
@rem __build\android\<abi>\defaultlib\*.d.ts ...
@rem Output, into the one default-library tree every target shares (a program compiled for Android
@rem takes --default-lib-path=__build, the directory holding defaultlib\, as any other does):
@rem __build\defaultlib\lib\<arch>\unknown\linux\android\<mode>\<model>\libTypeScriptDefaultLib.a
@rem (arch: aarch64 for arm64-v8a, x86_64 for x86_64; tslang --print-default-lib-dir names it)
@rem __build\defaultlib\*.d.ts ... (shared by every target)
@rem
@rem Differences from build.sh:
@rem - HTTP is src\wrappers\http_stub.cpp, not http_linux.cpp: libcurl is not part of Android, so
Expand Down Expand Up @@ -93,9 +94,19 @@ set CXX="%NDK_BIN%\clang++.exe" --target=%TRIPLE% -fPIC -std=c++17 %DBG_CXX%
set AR="%NDK_BIN%\llvm-ar.exe"
set TSC=%TSLANG% -mtriple=%TRIPLE% -relocation-model=pic %DBG% -mm=%MM% --emit=obj --export=none --nowarn --no-default-lib

set OUT=%ROOT%\__build\android\%ABI%\defaultlib
set OBJ=%ROOT%\__build\android\%ABI%\obj-%MODE%-%MM%
set LIB_OUT=%OUT%\lib\%MODE%\%MM%
rem The archive's folder, from tslang itself with the flags it compiles with below, composed the
rem way tslang later looks it up (see tslang/include/TypeScript/Defines.h).
set LIB_DIR=
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"
if "%LIB_DIR%"=="" (
echo %TSLANG% cannot name the output folder ^(--print-default-lib-dir^): it predates the per-target layout
exit /b 1
)
set "LIB_DIR=%LIB_DIR:/=\%"

set OUT=%ROOT%\__build\defaultlib
set OBJ=%ROOT%\__build\obj-android-%ABI%-%MODE%-%MM%
set LIB_OUT=%ROOT%\__build\%LIB_DIR%

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

rd /s /q "%OBJ%"

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