-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathbootstrap.sh
More file actions
executable file
·247 lines (212 loc) · 9.31 KB
/
Copy pathbootstrap.sh
File metadata and controls
executable file
·247 lines (212 loc) · 9.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#!/usr/bin/env bash
#
# The Jou compiler is written in Jou, but it doesn't help you very much if you
# have nothing that can compile or run Jou code. That's why this script exists.
#
# See the bootstrapping section in README.md for details.
#
# If you just want to setup a Jou development environment, you probably don't
# need to run this script manually, because `make` runs it as needed.
set -e -o pipefail
# Add the latest commit on main branch to the end of the list if this script
# produces a compiler that is too old. This means that whatever the script is
# currently producing will be used to compile the commit you add.
#
# The numbering does not start from 0 for historical reasons. Commit 001 was
# just before the original compiler written in C was deleted.
numbered_commits=(
030_bb3dc7d925fa28ce405fda5a4fc3c428f6f7c2b1 # <--- "./windows_setup.sh --small" starts from here! (release 2026-03-16-0500)
031_03b1e1e19d97777ff3e06deebd090d8618eb4287 # needed on 32-bit systems (contains fix of #1127)
032_e0eeac1528ac6beada7cc0d3061b2b7e9ba9e6a6 # release 2026-05-30-2200
)
# This should be an item of the above list according to what
# bootstrap_transpiler.py supports.
bootstrap_transpiler_numbered_commit=030_bb3dc7d925fa28ce405fda5a4fc3c428f6f7c2b1
if [[ "${OS:=$(uname)}" =~ Windows ]]; then
source activate
exe_suffix=".exe"
else
exe_suffix=""
fi
CYAN="\x1b[36m"
RED="\x1b[31m"
RESET="\x1b[0m"
# On windows, you get a linker error if you try to compile LLVM code without these files.
#
# The same list of files is in:
# - .github/workflows/windows.yml
# - compiler/llvm.jou
windows_llvm_files=(
mingw64/lib/libLLVMCore.dll.a
mingw64/lib/libLLVMX86CodeGen.dll.a
mingw64/lib/libLLVMAnalysis.dll.a
mingw64/lib/libLLVMTarget.dll.a
mingw64/lib/libLLVMPasses.dll.a
mingw64/lib/libLLVMSupport.dll.a
mingw64/lib/libLLVMLinker.dll.a
mingw64/lib/libLTO.dll.a
mingw64/lib/libLLVMX86AsmParser.dll.a
mingw64/lib/libLLVMX86Info.dll.a
mingw64/lib/libLLVMX86Desc.dll.a
mingw64/lib/libLLVMBitReader.dll.a
mingw64/lib/libLLVMBitWriter.dll.a
)
function transpile_with_python_and_compile() {
echo -e "${CYAN}$0: Let's use Python to convert a Jou compiler to C code.${RESET} "
echo -n "Finding Python... "
if [[ "${OS:=$(uname)}" =~ Windows ]]; then
# Avoid the "python.exe" launcher that opens app store for installing python.
python=$(command -v py python | grep -v Microsoft/WindowsApps | head -1 || true)
else
python=$(command -v python3 python python3.{10..20} | head -1 || true)
fi
echo "$python"
if ! [[ "$("$python" --version || true)" =~ ^Python\ 3 ]]; then
echo -e "${RED}Error: Python not found. Please install it.${RESET}" >&2
echo "Also, please create an issue on GitHub if you can't get this to work." >&2
exit 1
fi
echo -n "Finding clang... "
if [[ "${OS:=$(uname)}" =~ Windows ]]; then
clang="$PWD/mingw64/bin/clang.exe"
else
clang="$(grep '^const JOU_CLANG_PATH:' config.jou | cut -d'"' -f2)"
fi
echo "$clang"
if ! [ -f "$clang" ]; then
echo -e "${RED}Error: clang not found.${RESET}" >&2
echo "Please create an issue on GitHub if you can't get this to work." >&2
exit 1
fi
local folder=tmp/bootstrap_cache/$bootstrap_transpiler_numbered_commit
local number=${bootstrap_transpiler_numbered_commit%%_*}
local commit=${bootstrap_transpiler_numbered_commit#*_}
echo "Checking out commit $number into $folder"
rm -rf $folder
mkdir -p $folder
git archive --format=tar $commit | (cd $folder && tar xf -)
cp -v config.jou $folder || true
if [[ "$OS" =~ Windows ]]; then
echo "Copying LLVM files..."
mkdir -p $folder/mingw64/lib
cp -v ${windows_llvm_files[@]} $folder/mingw64/lib/
fi
(
cd $folder
echo "Converting Jou code to C..."
local n
n=$(getconf _NPROCESSORS_ONLN)
"$python" ../../../bootstrap_transpiler.py --split $n compiler/main.jou > compiler.c
echo "Compiling C code... ($n parallel processes)"
local i
target=$(grep JOU_TARGET config.jou | awk -F '"' '{ if ($2) print "-target " $2}' || true)
for i in $(seq 1 $n); do
# TODO: -w silences all warnings. We might not want that in the future.
#
# TODO: On windows, this needs at least -O2 because the C code is so
# bad it overflows the stack if optimizer doesn't reduce stack
# usage!!! Instead emit better C code? Or at least handle union
# members, or don't create so many local variables? Last time it
# failed on creating an AstExpression on stack with all the
# different kinds of expressions as struct members instead of
# union members...
#
# UPDATE: We hit the Windows stack limit again... and I just
# bumped it to 16M instead of the default 1M. Maybe some day I
# will clean this up :)
$clang -w -O2 $target -c compiler.c -o compiler$i.o -DSPLIT$i &
done
# Unlike a plain "wait", this loop doesn't ignore failures inside individual jobs.
for i in $(seq 1 $n); do wait -n; done
echo "Linking C code..."
if [[ "$OS" =~ Windows ]]; then
# TODO: stack size is a hack... see above
$clang compiler*.o -o jou_from_c.exe -pthread -Wl,--stack,16777216 ${windows_llvm_files[@]}
else
$clang compiler*.o -o jou_from_c -pthread $(grep ^link config.jou | cut -d'"' -f2)
fi
# Transpiling produces a broken Jou compiler for some reason. I don't
# know why. But if I recompile once more, it fixes itself.
echo "Compiling the same Jou code again with the compiler we just made..."
if [[ "$OS" =~ Windows ]]; then
# Use correct path to mingw64. This used to copy the mingw64 folder,
# but it was slow and wasted disk space. Afaik symlinks aren't really a
# thing on windows.
JOU_MINGW_DIR=../../../mingw64 ./jou_from_c.exe -o jou.exe compiler/main.jou
else
./jou_from_c -o jou compiler/main.jou
fi
)
}
function compile_next_jou_compiler() {
local previous_numbered_commit=$1
local numbered_commit=$2
local previous_folder=tmp/bootstrap_cache/$previous_numbered_commit
local previous_number=${previous_numbered_commit%%_*}
local folder=tmp/bootstrap_cache/$numbered_commit
local number=${numbered_commit%%_*}
local commit=${numbered_commit#*_}
echo -e "${CYAN}$0: Using the previous Jou compiler to compile the next Jou compiler.${RESET} ($previous_number --> $number)"
echo "Checking out commit $number into $folder"
rm -rf $folder
mkdir -p $folder
git archive --format=tar $commit | (cd $folder && tar xf -)
cp -v config.jou $folder || true
echo "Copying previous executable..."
cp -v $previous_folder/jou$exe_suffix $folder/jou_bootstrap$exe_suffix
if [[ "$OS" =~ Windows ]]; then
echo "Copying LLVM files..."
mkdir -p $folder/mingw64/lib
cp ${windows_llvm_files[@]} $folder/mingw64/lib/
fi
(
cd $folder
echo "Deleting version check..."
sed -i -e "/Found unsupported LLVM version/d" Makefile.*
echo "Compiling Jou compiler with the previous Jou compiler..."
# We don't do this with make, because it might decide to build
# jou_bootstrap(.exe) for whatever reason, and we don't want bootstrap
# inside bootstrap.
if [[ "$OS" =~ Windows ]]; then
# Use correct path to mingw64. This used to copy the mingw64 folder,
# but it was slow and wasted disk space. Afaik symlinks aren't really a
# thing on windows.
JOU_MINGW_DIR=../../../mingw64 ./jou_bootstrap.exe -o jou.exe compiler/main.jou
else
./jou_bootstrap -o jou compiler/main.jou
fi
)
}
# Figure out how far back in history we need to go.
# If nothing exists, use the bootstrap transpiler script.
numbered_commit=
for (( i = ${#numbered_commits[@]}-1 ; i >= 0 ; i-- )) ; do
if [ -f tmp/bootstrap_cache/${numbered_commits[i]}/jou$exe_suffix ]; then
numbered_commit=${numbered_commits[i]}
echo -e "${CYAN}$0: Found a previously built executable for commit ${numbered_commit%%_*} (${numbered_commit#*_}).${RESET}"
echo "Delete tmp/bootstrap_cache/${numbered_commit} if you want to build it again."
break
fi
done
if [ -z "$numbered_commit" ]; then
transpile_with_python_and_compile
numbered_commit=$bootstrap_transpiler_numbered_commit
fi
while true; do
previous_numbered_commit=$numbered_commit
# Find next commit
for (( i = 0 ; i < ${#numbered_commits[@]} ; i++ )) ; do
if [ ${numbered_commits[i]} == $numbered_commit ]; then
numbered_commit=${numbered_commits[i+1]}
break
fi
done
if [ -z "$numbered_commit" ]; then
# Reached end of list
break
fi
compile_next_jou_compiler $previous_numbered_commit $numbered_commit
done
echo -e "${CYAN}$0: Copying the bootstrapped executable...${RESET}"
cp -v tmp/bootstrap_cache/$previous_numbered_commit/jou$exe_suffix ./jou_bootstrap$exe_suffix
echo -e "${CYAN}$0: Done!${RESET}"