-
-
Notifications
You must be signed in to change notification settings - Fork 610
Expand file tree
/
Copy pathbuild
More file actions
executable file
·483 lines (435 loc) · 16.4 KB
/
Copy pathbuild
File metadata and controls
executable file
·483 lines (435 loc) · 16.4 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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
#!/usr/bin/env bash
# This script replaces our old "make" command line - instead of
# "make mode=debug image=rogue", use "build mode=debug image=rogue".
# This first runs "make" with the same parameters, and then builds
# the requested image.
usage() {
cat <<-EOF
Build OSv kernel and specified modules/apps and package them together into a runnable image
This bash shell script acts as a top level orchestration tool intended to build
OSv images. It does so by invoking a make against the main OSv makefile to
build the kernel and then delegates to various Python scripts (scripts/module.py)
to orchestrate building of explicitly specified apps and modules as well as any
implicitly dependant ones. The end result is the build/<mode>/usr.img file that
is composed of OSv kernel (loader-stripped.elf) and application files and can be
executed using ./scripts/run.py.
Usage:
scripts/build [options] image=<app1>[,<app2[.run_conf]>[,<module1>,..]] modules=<module1>[,..] | check
scripts/build clean
Options:
--help|-h Print this help message
arch=x64|aarch64 Specify the build architecture; default is the same as build host arch
mode=release|debug Specify the build mode; default is release
export=none|selected|all If 'selected' or 'all' export the app files to <export_dir>
export_dir=<dir> The directory to export the files to; default is build/export
fs=zfs|rofs|ext|ramfs|virtiofs Specify the filesystem of the image partition
|rofs_with_zfs|rofs_with_ext
fs_size=N Specify the size of the image in bytes
fs_size_mb=N Specify the size of the image in MiB
app_local_exec_tls_size=N Specify the size of app local TLS in bytes; the default is 64
usrskel=<*.skel> Specify the base manifest for the image
<module_makefile_arg>=<value> Pass value of module_makefile_arg to an app/module makefile
(can be used to customize specific app/module build process)
-j<N> Set number of parallel jobs for make
--append-manifest Append build/<mode>/append.manifest to usr.manifest
--create-disk Instead of usr.img create kernel-less disk.img
--create-zfs-disk Create extra empty disk with ZFS filesystem
--use-openzfs Build and manipulate ZFS images using on host OpenZFS tools
Examples:
./scripts/build -j4 fs=rofs image=native-example # Create image with native-example app
./scripts/build JAVA_VERSION=10 image=openjdk-zulu-9-and-above,spring-boot-example
# Create image with spring boot app with Java 10 jdk
./scripts/manifest_from_host.sh -w ls && ./script/build --append-manifest
# Create manifest for 'ls' executable
./script/build check # Create test image and run all tests in it
./script/build clean # Clean the build tree
EOF
exit ${1:-0}
}
trap 'echo "$0 failed: $BASH_COMMAND" >&2; exit $?' ERR
# If "MAKEFLAGS" is set, we've been run from "make". The following hacks
# allows our Makefile to forward "make image=..." requests to to us
# without running into an infinite loop when we call "make".
MAKEFLAGS=${MAKEFLAGS/ image=/ zzz=}
MAKEFLAGS=${MAKEFLAGS/#image=/zzz=}
MAKEFLAGS=${MAKEFLAGS/ modules=/ zzz=}
MAKEFLAGS=${MAKEFLAGS/#modules=/zzz=}
unset image modules
# Pass to "make" all the given args except "image=..." or "module=..."
declare -a args
# Make is going to be invoked twice. At the first run ("stage1") we
# build all possible dependencies any app or module might require. At
# the second - the loader.elf is linked and the loader.img is
# produced. In the case of "make clean", the first invocation (and
# the only one) is used for cleaning up the kernel.
stage1_args="stage1"
for i
do
case $i in
--help|-h)
usage ;;
image=*|modules=*|fs=*|usrskel=*|check|--append-manifest|--create-disk|--create-zfs-disk|--use-openzfs) ;;
clean)
stage1_args=clean ;;
arch=*)
eval ${i}
args+=("$i") ;;
*)
args+=("$i") ;;
esac
done
if [[ "${arch-}" == "aarch64" && -d "build/downloaded_packages/aarch64/toolchain/" ]]; then
. scripts/download_aarch64_toolchain.sh
export CROSS_PREFIX=aarch64-none-linux-gnu-
fi
make "${args[@]}" -f conf/Makefile -j1 config | tee build.out
# check exit status of make
status=${PIPESTATUS[0]}
if [ $status -ne 0 ]
then
echo "make -f conf/Makefile failed. Exiting from build script"
exit $status
fi
make "${args[@]}" ${stage1_args} | tee build.out
# check exit status of make
status=${PIPESTATUS[0]}
if [ $status -ne 0 ]
then
echo "make failed. Exiting from build script"
exit $status
fi
for i
do
case $i in
clean) # "build clean" is like "make clean" to clean the kernel,
# plus additional cleanups of all modules.
set -x
OSV_BASE=`pwd` ./scripts/module.py clean -q
exit;;
esac
done
# Find out where "make" decided to put its compilation results. We'll
# put the images in the same place.
if test ! -L build/last -o ! -f build/last/loader.o
then
echo "'make stage1' did not leave expected results" >&2
exit 2
fi
OUT=build/`readlink build/last`
# Look for arguments that look like "name=value", and set them in an
# assoative array "vars". Also look for the "-j ..." parallelism option,
# which we want to pass to the module's Makefile as well.
declare -A vars
j_arg=
checknumber=
for i
do
if test -n "$checknumber"
then
checknumber=
case $i in
[0-9]*)
j_arg="-j$i"
continue;;
esac
fi
case $i in
*=*) name=${i%%=*}
value=${i#*=}
vars[$name]=$value;;
-j)
# module.py's command line parser has trouble of parsing a
# "-j" option without a value. Help it with a fake value "-".
j_arg="-j-"
# make allows the "-j" option to be separated from the number by a
# space (e.g., "-j 4"), but since this number is optional, we will
# need to also check the next argument, whether it is a number.
checknumber=yes;;
-j*) j_arg=$i;;
check) # "build check" is a shortcut for
# "build image=tests; scripts/test.py"
vars[image]=tests;;
--append-manifest)
vars[append_manifest]="true";;
--create-disk)
vars[create_disk]="true";;
--create-zfs-disk)
vars[create_zfs_disk]="true";;
--use-openzfs)
vars[use_openzfs]="true";;
esac
done
# fs_size_mb is in megabytes (1024*1024 bytes)
fs_size_mb=${vars[fs_size_mb]-512}
# fs_size is in bytes
fs_size=${vars[fs_size]-$(($fs_size_mb*1024*1024))}
# size must be a multiple of 512. Round it down
fs_size=$((fs_size - (fs_size & 511)))
SRC=`pwd`
arch=`expr $OUT : '.*\.\(.*\)'`
mode=`expr $OUT : '.*/\(.*\)\..*'`
# Set "modules" according to the image= or modules= parameters, or some
# defaults (with same rules as in our old makefile)
case $arch in
aarch64) image=${vars[image]-uush};;
*) image=${vars[image]-default};;
esac
modules=${vars[modules]-!$image}
case $OUT in
/*) OSV_BUILD_PATH=$OUT;;
*) OSV_BUILD_PATH=`pwd`/$OUT;;
esac
host_arch=$(uname -m)
# Default manifest
manifest=bootfs.manifest.skel
fs_type=${vars[fs]-zfs}
usrskel_arg=
case $fs_type in
zfs)
;; # Nothing to change here. This is our default behavior
ext)
cp "$SRC"/static/etc/fstab_ext "$OUT"/fstab
manifest=bootfs_ext.manifest.skel
usrskel_arg="--usrskel usr_ext.manifest.skel";;
rofs|rofs_with_zfs|rofs_with_ext|virtiofs)
# Both are read-only (in OSv) and require nothing extra on bootfs to work
manifest=bootfs_empty.manifest.skel
usrskel_arg="--usrskel usr_rofs.manifest.skel";;
ramfs)
cp "$SRC"/static/etc/fstab "$OUT"/fstab
manifest=$OUT/usr.manifest
usrskel_arg="--usrskel usr_ramfs.manifest.skel";;
*)
echo "Unknown filesystem \"$fs_type\"" >&2
exit 2
esac
if [[ "$host_arch" == "aarch64" || "$arch" == "aarch64" ]]; then
vars[create_disk]="true"
fi
if test -n "${vars[usrskel]}"
then
# Override default skel
usrskel_arg="--usrskel ${vars[usrskel]}"
fi
export=${vars[export]-none}
if [ "$export" == "selected" ]
then
no_required_arg="--no-required"
fi
if [[ ${vars[append_manifest]} == "true" && $modules == "!default" ]]; then
modules="empty"
fi
if [[ "$fs_type" == "ext" || "$fs_type" == "rofs_with_ext" ]]; then
modules="$modules,libext"
fi
CC=gcc
if [[ "$host_arch" == "x86_64" && "$arch" == 'aarch64' ]]; then
CC=${CROSS_PREFIX:-aarch64-linux-gnu-}gcc
fi
libgcc_s_path=$(${CC} -print-file-name=libgcc_s.so.1)
if [[ "$libgcc_s_path" == "libgcc_s.so.1" ]]; then
cat <<-EOF
Unable to resolve libgcc_s.so.1 using "${CC}".
Looking in build/downloaded_packages/aarch64/gcc/install/lib64
EOF
libgcc_s_path="build/downloaded_packages/aarch64/gcc/install/lib64/libgcc_s.so.1"
fi
libgcc_s_dir=$(dirname $(readlink -f ${libgcc_s_path}))
# The parentheses start a subshell. Whatever is exported there, doesn't affect the external shell
(
# Note: the double-quotes and almost everything in the line below is important to correctly allow spaces
# This specifically allows us to pass extra arguments to the modules/apps makefiles
for i in "${args[@]}"
do
case $i in
*=*)
# again, the double-quotes is important in case the variable's value contains spaces
export "$i" ;;
esac
done
# Export the variables we already have. This makes it unnecessary to do "fs__type=$fstype ..."
export fs_type mode OSV_BUILD_PATH libgcc_s_dir
# Other variables we wanted to rename, I don't know why
export ARCH=$arch OSV_BASE=$SRC
# Run what we wanted to run. It will inherit everything we exported above.
scripts/module.py $j_arg build -c "$modules" $usrskel_arg $no_required_arg
)
if [[ ${vars[append_manifest]} == "true" && -f "$OSV_BUILD_PATH/append.manifest" ]]; then
cat "$OSV_BUILD_PATH/append.manifest" >> "$OSV_BUILD_PATH/usr.manifest"
if [[ -f "$OSV_BUILD_PATH/append_cmdline" && $(cat "$OSV_BUILD_PATH/cmdline") == "" ]]; then
cp $OSV_BUILD_PATH/append_cmdline $OSV_BUILD_PATH/cmdline
fi
fi
fs=$fs_type bootfs_manifest=$manifest make "${args[@]}" | tee -a build.out
# check exit status of make
status=${PIPESTATUS[0]}
if [ $status -ne 0 ]
then
echo "make failed. Exiting from build script"
exit $status
fi
if test ! -f build/last/loader.img
then
echo "'make' did not leave expected results" >&2
exit 2
fi
loader_size=`stat --printf %s $OUT/loader.img`
kernel_end=$(($loader_size+2097151 & ~2097151))
# The python scripts called below assume the current directory is $OUT (as was
# the case in our old build.mk).
cd $OUT
if [ "$export" != "none" ]; then
export_dir=${vars[export_dir]-$SRC/build/export}
rm -rf "$export_dir"
"$SRC"/scripts/export_manifest.py -e "$export_dir" -m usr.manifest -D libgcc_s_dir="$libgcc_s_dir"
fi
if [[ ${vars[create_disk]} == "true" ]]; then
partition_offset=512
bare="$SRC"/scripts/disk.bin
raw_disk=disk
qcow2_disk=disk
else
partition_offset=$kernel_end
bare=loader.img
raw_disk=bare
qcow2_disk=usr
fi
create_zfs_disk() {
cp $bare $raw_disk.raw
"$SRC"/scripts/imgedit.py setpartition "-f raw ${raw_disk}.raw" 2 $partition_offset $partition_size
if [[ ${vars[use_openzfs]} == "true" ]]; then
#We use raw disk on purpose so that zfs-image-on-host.sh can use loop device which is faster to copy files to
qemu-img resize ${raw_disk}.raw ${image_size}b >/dev/null 2>&1
"$SRC"/scripts/zfs-image-on-host.sh build ${raw_disk}.raw 1 osv zfs true
qemu-img convert -f raw -O qcow2 $raw_disk.raw $qcow2_disk.img
else
qemu-img convert -f raw -O qcow2 $raw_disk.raw $qcow2_disk.img
qemu-img resize $qcow2_disk.img ${image_size}b >/dev/null 2>&1
"$SRC"/scripts/upload_manifest.py --arch=$arch -o $qcow2_disk.img -m usr.manifest -D libgcc_s_dir="$libgcc_s_dir"
fi
rm ${raw_disk}.raw
}
create_ext_disk() {
cp $bare $raw_disk.raw
"$SRC"/scripts/imgedit.py setpartition "-f raw ${raw_disk}.raw" 2 $partition_offset $partition_size
qemu-img resize ${raw_disk}.raw ${image_size}b >/dev/null 2>&1
dd if=disk.ext of=${raw_disk}.raw obs=$partition_offset seek=1 >/dev/null 2>&1
qemu-img convert -f raw -O qcow2 $raw_disk.raw $qcow2_disk.img
}
create_rofs_disk() {
cp $bare $raw_disk.raw
"$SRC"/scripts/imgedit.py setpartition "-f raw ${raw_disk}.raw" 2 $partition_offset $partition_size
qemu-img resize ${raw_disk}.raw ${image_size}b >/dev/null 2>&1
dd if=rofs.img of=${raw_disk}.raw obs=$partition_offset seek=1 >/dev/null 2>&1
qemu-img convert -f raw -O qcow2 $raw_disk.raw $qcow2_disk.img
qemu-img resize $qcow2_disk.img ${image_size}b >/dev/null 2>&1
}
create_zfs_filesystem() {
local image_path=$1
if [[ ${vars[use_openzfs]} == "true" ]]; then
local partition=$3
"$SRC"/scripts/zfs-image-on-host.sh build $image_path $partition osv zfs false
else
local device_path=$2
local qemu_arch=$arch
if [[ "$qemu_arch" == 'aarch64' ]]; then
console=''
zfs_builder_name='zfs_builder.img'
else
qemu_arch='x86_64'
console='--console=serial'
zfs_builder_name='zfs_builder-stripped.elf'
fi
"$SRC"/scripts/run.py -k --kernel-path $zfs_builder_name --arch=$qemu_arch --vnc none -m 512 -c1 -i ${image_path} --block-device-cache writeback \
-s -e "${console} --norandom --nomount --noinit --preload-zfs-library /tools/mkfs.so ${device_path}; /zfs.so set compression=off osv"
fi
}
if [[ "$host_arch" == "x86_64" && "$arch" == 'aarch64' ]]; then
export STRIP=${CROSS_PREFIX:-aarch64-linux-gnu-}strip
fi
case $fs_type in
zfs)
partition_size=$((fs_size - partition_offset))
image_size=$fs_size
cp "$SRC"/static/etc/fstab fstab
create_zfs_disk ;;
ext)
rm -rf disk.ext
"$SRC"/scripts/ext-disk-utils.sh create disk.ext $(((fs_size - partition_offset)/(1024*1024))) true
partition_size=`stat --printf %s disk.ext`
image_size=$fs_size
create_ext_disk ;;
rofs)
rm -rf rofs.img
cp "$SRC"/static/etc/fstab_rofs fstab
if [[ ${vars[create_zfs_disk]} == "true" ]]; then
echo "/dev/vblk1.1 /data zfs defaults 0 0" >> fstab
fi
"$SRC"/scripts/gen-rofs-img.py -o rofs.img -m usr.manifest -D libgcc_s_dir="$libgcc_s_dir"
partition_size=`stat --printf %s rofs.img`
image_size=$fs_size
create_rofs_disk ;;
rofs_with_zfs|rofs_with_ext)
# Create disk with rofs image on it 1st partition
rm -rf rofs.img
cp "$SRC"/static/etc/fstab_rofs fstab
if [[ "$fs_type" == "rofs_with_zfs" ]]; then
echo "/dev/vblk0.2 /data zfs defaults 0 0" >> fstab
else
echo "/dev/vblk0.2 /data ext defaults 0 0" >> fstab
fi
"$SRC"/scripts/gen-rofs-img.py -o rofs.img -m usr.manifest -D libgcc_s_dir="$libgcc_s_dir"
partition_size=`stat --printf %s rofs.img`
image_size=$((fs_size+partition_size))
create_rofs_disk
# Resize the disk to fit ext or zfs on it after rofs
qemu-img resize $qcow2_disk.img ${image_size}b >/dev/null 2>&1
snd_partition_offset=$((partition_offset + partition_size))
snd_partition_size=$((image_size-snd_partition_offset))
"$SRC"/scripts/imgedit.py setpartition "$qcow2_disk.img" 3 $snd_partition_offset $snd_partition_size
# Create filesystem on ZFS/EXT partition
if [[ "$fs_type" == "rofs_with_zfs" ]]; then
create_zfs_filesystem $qcow2_disk.img "/dev/vblk0.2" 2
else
rm -rf disk.ext
"$SRC"/scripts/ext-disk-utils.sh create disk.ext $((snd_partition_size/(1024*1024)))
qemu-img convert -f qcow2 -O raw $qcow2_disk.img $raw_disk.raw
dd if=disk.ext of=${raw_disk}.raw obs=$snd_partition_offset seek=1 >/dev/null 2>&1
qemu-img convert -f raw -O qcow2 $raw_disk.raw $qcow2_disk.img
fi ;;
ramfs|virtiofs)
# No need to create extra fs like above: ramfs is already created (as the
# bootfs) and virtio-fs is specified with virtiofsd at run time
image_size=$((partition_offset))
cp $bare $raw_disk.raw
"$SRC"/scripts/imgedit.py setpartition "-f raw ${raw_disk}.raw" 2 $partition_offset 0
qemu-img resize ${raw_disk}.raw ${image_size}b >/dev/null 2>&1
qemu-img convert -f raw -O qcow2 $raw_disk.raw $qcow2_disk.img ;;
esac
# Prepend the root fs type option to the command line (preserved by run.py)
cmdline=$(cat cmdline)
echo -n "--rootfs=${fs_type} ${cmdline}" > cmdline
if [[ -f "$OSV_BUILD_PATH/usr.img" ]]; then
"$SRC"/scripts/imgedit.py setargs usr.img `cat cmdline`
fi
if [[ ${vars[create_zfs_disk]} == "true" ]]; then
partition_offset=512
partition_size=$((fs_size - partition_offset))
image_size=$fs_size
raw_disk=zfs_disk
qcow2_disk=zfs_disk
cp "$SRC"/scripts/disk.bin $raw_disk.raw
"$SRC"/scripts/imgedit.py setpartition "-f raw ${raw_disk}.raw" 2 $partition_offset $partition_size
qemu-img convert -f raw -O qcow2 $raw_disk.raw $qcow2_disk.img
qemu-img resize $qcow2_disk.img ${image_size}b >/dev/null 2>&1
create_zfs_filesystem $qcow2_disk.img "/dev/vblk0.1" 1
fi
# Support "build check"
for i
do
case $i in
check) set -x
cd "$SRC"
exec ./scripts/test.py
esac
done