442 lines
15 KiB
Perl
442 lines
15 KiB
Perl
#!/usr/bin/env perl
|
|
|
|
use strict;
|
|
use warnings;
|
|
use feature 'say';
|
|
use File::Copy qw(copy);
|
|
use File::Path qw(rmtree make_path);
|
|
use Cwd qw(abs_path);
|
|
use FindBin;
|
|
use lib "$FindBin::Bin/Modules";
|
|
use Util;
|
|
|
|
# ========================================================================================= #
|
|
# Project root
|
|
# ========================================================================================= #
|
|
|
|
my $root = abs_path("$FindBin::Bin/..");
|
|
chdir($root) or die "Cannot chdir to $root: $!\n";
|
|
|
|
# ========================================================================================= #
|
|
# Environment set by "nix develop"
|
|
# ========================================================================================= #
|
|
|
|
sub require_env {
|
|
my ($name) = @_;
|
|
return $ENV{$name}
|
|
// die "$name is not set (run from 'nix develop' shell)\n";
|
|
}
|
|
|
|
my $wasi_root = require_env('WASI_ROOT');
|
|
my $wamr_root = require_env('WAMR_ROOT');
|
|
my $cross_cc = require_env('CROSS_CC');
|
|
my $linux_cc = require_env('LINUX_CC');
|
|
|
|
my $use_aot_in_text = ( $ENV{WAMR_USE_AOT_IN_TEXT} // 'false' ) eq 'true';
|
|
my $use_mmap_in_text = ( $ENV{WAMR_USE_MMAP_IN_TEXT} // 'false' ) eq 'true';
|
|
my $use_xip = ( $ENV{WAMR_USE_XIP} // 'false' ) eq 'true';
|
|
my $use_allocator = ( $ENV{WAMR_USE_ALLOCATOR} // 'false' ) eq 'true';
|
|
my $use_global_heap_in_text =
|
|
( $ENV{WAMR_USE_GLOBAL_HEAP_IN_TEXT} // 'false' ) eq 'true';
|
|
my $use_runtime_pool_in_text =
|
|
( $ENV{WAMR_USE_RUNTIME_POOL_IN_TEXT} // 'false' ) eq 'true';
|
|
my $use_linear_pool_in_text =
|
|
( $ENV{WAMR_USE_LINEAR_POOL_IN_TEXT} // 'false' ) eq 'true';
|
|
|
|
# ========================================================================================= #
|
|
# WAMR cmake configuration
|
|
# ========================================================================================= #
|
|
|
|
# Flags common to all platforms
|
|
my @wamr_cmake_base = (
|
|
'-DCMAKE_BUILD_TYPE=Debug', '-DWAMR_BUILD_TARGET=X86_32',
|
|
'-DWAMR_BUILD_AOT=1', '-DWAMR_BUILD_WAMR_COMPILER=0',
|
|
'-DWAMR_BUILD_INTERP=1', '-DWAMR_BUILD_FAST_INTERP=0',
|
|
'-DWAMR_BUILD_JIT=0', '-DWAMR_BUILD_FAST_JIT=0',
|
|
'-DWAMR_BUILD_LIBC_BUILTIN=1', '-DWAMR_BUILD_LIBC_WASI=0',
|
|
'-DWAMR_BUILD_SIMD=0',
|
|
);
|
|
|
|
my @wamr_cmake_baremetal = (
|
|
'-DWAMR_BUILD_PLATFORM=baremetal',
|
|
'-DCMAKE_SYSTEM_NAME=Generic',
|
|
'-DCMAKE_SYSTEM_PROCESSOR=i386',
|
|
'-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY',
|
|
);
|
|
|
|
my @wamr_cmake_linux = ( '-DWAMR_BUILD_PLATFORM=linux', );
|
|
|
|
# Variant defines passed as CMAKE_C_FLAGS
|
|
my @variant_cflags =
|
|
( '-Wno-error=implicit-function-declaration', '-O0', '-ggdb3' );
|
|
push @variant_cflags,
|
|
$use_mmap_in_text ? '-DWAMR_MMAP_IN_TEXT=1' : '-DWAMR_MMAP_IN_TEXT=0';
|
|
push @variant_cflags, '-DWASM_MEM_ALLOC_WITH_USAGE=1' if $use_allocator;
|
|
my $cmake_c_flags = join( ' ', @variant_cflags );
|
|
|
|
# Variant options passed as cmake variables
|
|
my @variant_cmake_flags;
|
|
push @variant_cmake_flags, '-DWAMR_BUILD_ALLOC_WITH_USAGE=1' if $use_allocator;
|
|
|
|
# Defines forwarded to the host compilation so wasm_host.c sees the same
|
|
# WASM_MEM_ALLOC_WITH_USAGE value as libiwasm.a was built with.
|
|
my @host_variant_cflags;
|
|
push @host_variant_cflags, '-DWASM_MEM_ALLOC_WITH_USAGE=1' if $use_allocator;
|
|
push @host_variant_cflags,
|
|
$use_global_heap_in_text
|
|
? '-DWAMR_GLOBAL_HEAP_IN_TEXT=1'
|
|
: '-DWAMR_GLOBAL_HEAP_IN_TEXT=0';
|
|
push @host_variant_cflags,
|
|
$use_runtime_pool_in_text
|
|
? '-DWAMR_RUNTIME_POOL_IN_TEXT=1'
|
|
: '-DWAMR_RUNTIME_POOL_IN_TEXT=0';
|
|
push @host_variant_cflags,
|
|
$use_linear_pool_in_text
|
|
? '-DWAMR_LINEAR_POOL_IN_TEXT=1'
|
|
: '-DWAMR_LINEAR_POOL_IN_TEXT=0';
|
|
|
|
# ========================================================================================= #
|
|
# Compiler / linker flags
|
|
# ========================================================================================= #
|
|
|
|
my @wasi_cflags = (
|
|
'--target=wasm32', "--sysroot=$wasi_root/share/wasi-sysroot",
|
|
'-z', 'stack-size=4096',
|
|
'-O0', '-nostdlib',
|
|
'-Wl,--no-entry', '-Wl,--export=wasm_module',
|
|
'-Wl,--no-gc-sections', '-Wl,--initial-memory=65536',
|
|
'-Wl,--export=__heap_base', '-Wl,--export=__data_end',
|
|
);
|
|
|
|
my @cross_cflags =
|
|
qw(-O0 -m32 -ffunction-sections -fdata-sections -ffreestanding -fpermissive -ggdb3);
|
|
my @linux_cflags =
|
|
qw(-O0 -m32 -ffunction-sections -fdata-sections -fpermissive -ggdb3);
|
|
my @linux_baremetal_cflags =
|
|
qw(-O0 -m32 -ffunction-sections -fdata-sections -ffreestanding -ggdb3);
|
|
|
|
# libiwasm.a is passed as a direct file path (no -L/-liwasm)
|
|
my @cross_ldflags_base = (
|
|
'-Wl,--build-id=none', '-static', '-nostdlib', '-m32',
|
|
'-lc', '-lgcc', '-lm'
|
|
);
|
|
my @linux_ldflags_base = ( '-Wl,--build-id=none', '-m32', '-lm' );
|
|
my @baremetal_ldflags_base = (
|
|
'-Wl,--build-id=none', '-static', '-nostdlib', '-m32',
|
|
'-lc', '-lgcc', '-lm', '--entry',
|
|
'main'
|
|
);
|
|
my @cross_ldflags_nowasm = (
|
|
'-Wl,--build-id=none', '-static', '-nostdlib', '-m32',
|
|
'-lc', '-lgcc', '-lm'
|
|
);
|
|
my @linux_ldflags_nowasm = ( '-Wl,--build-id=none', '-m32', '-lm' );
|
|
|
|
my @wamr_inc_baremetal = (
|
|
"-I$wamr_root/core/iwasm/include",
|
|
"-I$wamr_root/core/shared/utils",
|
|
"-I$wamr_root/core/shared/platform/baremetal",
|
|
);
|
|
my @wamr_inc_linux = (
|
|
"-I$wamr_root/core/iwasm/include",
|
|
"-I$wamr_root/core/shared/utils",
|
|
"-I$wamr_root/core/shared/platform/linux",
|
|
);
|
|
|
|
my @cross_wamrcflags = ( '--target=i386', '--cpu=generic', '--opt-level=0' );
|
|
push @cross_wamrcflags, '--xip' if $use_xip;
|
|
my @linux_wamrcflags = ( '--target=i386', '--cpu=generic', '--opt-level=0' );
|
|
|
|
# ========================================================================================= #
|
|
# Entry point
|
|
# ========================================================================================= #
|
|
|
|
die "Usage: compile.pl <module> <target> <mode>\n"
|
|
. " target: fail | linux | linux-baremetal\n"
|
|
. " mode: aot | interp | c\n"
|
|
unless @ARGV == 3;
|
|
|
|
my ( $module, $target, $mode ) = @ARGV;
|
|
|
|
build( $module, $target, $mode );
|
|
|
|
# ========================================================================================= #
|
|
# Build
|
|
# ========================================================================================= #
|
|
|
|
sub build {
|
|
my ( $module, $target, $mode ) = @_;
|
|
my $bd = "build-$module";
|
|
|
|
rmtree($bd);
|
|
make_path($bd);
|
|
copy_auxiliary( $module, $bd );
|
|
|
|
if ( $mode eq 'aot' || $mode eq 'interp' ) {
|
|
build_libiwasm( $module, $bd, $target );
|
|
compile_wasm_module( $module, $bd );
|
|
if ( $mode eq 'aot' ) {
|
|
compile_wasm_aot( $module, $bd, $target );
|
|
make_aot_array( $module, $bd );
|
|
}
|
|
else {
|
|
make_interp_array( $module, $bd );
|
|
}
|
|
prepare_wasm_host( $module, $bd, $mode );
|
|
compile_wasm_host( $module, $bd, $target );
|
|
compile_startup( $module, $bd, $target );
|
|
compile_syscalls( $module, $bd, $target );
|
|
link_wasm( $module, $bd, $target );
|
|
}
|
|
elsif ( $mode eq 'c' ) {
|
|
compile_c_module( $module, $bd, $target );
|
|
compile_c_host( $module, $bd, $target );
|
|
compile_startup( $module, $bd, $target );
|
|
link_c( $module, $bd, $target );
|
|
}
|
|
else {
|
|
die "Unknown mode '$mode'; expected: aot, interp, c\n";
|
|
}
|
|
|
|
build_iso( $module, $bd );
|
|
}
|
|
|
|
# ========================================================================================= #
|
|
# Steps
|
|
# ========================================================================================= #
|
|
|
|
sub build_libiwasm {
|
|
my ( $module, $bd, $target ) = @_;
|
|
my $cmake_bd = "$bd/wamr-build";
|
|
make_path($cmake_bd);
|
|
|
|
my ( $cmake_cc, @sys_flags ) =
|
|
( $target eq 'linux' )
|
|
? ( $linux_cc, @wamr_cmake_linux )
|
|
: ( $cross_cc, @wamr_cmake_baremetal );
|
|
|
|
Util::run(
|
|
'cmake', '-S',
|
|
$wamr_root, '-B',
|
|
$cmake_bd, "-DCMAKE_C_COMPILER=$cmake_cc",
|
|
@wamr_cmake_base, @sys_flags,
|
|
@variant_cmake_flags, "-DCMAKE_C_FLAGS=$cmake_c_flags",
|
|
);
|
|
Util::run( 'cmake', '--build', $cmake_bd );
|
|
copy( "$cmake_bd/libiwasm.a", "$bd/libiwasm.a" )
|
|
or die "failed to copy $cmake_bd/libiwasm.a: $!";
|
|
rmtree($cmake_bd) or die "failed to remove $cmake_bd: $!";
|
|
}
|
|
|
|
sub copy_auxiliary {
|
|
my ( $module, $bd ) = @_;
|
|
my @files = (
|
|
[ 'flake.nix', "$bd/flake.nix" ],
|
|
[ 'scripts/runner.pl', "$bd/runner.pl" ],
|
|
[ 'scripts/compile.pl', "$bd/compile.pl" ],
|
|
[ 'targets/lib.h', "$bd/lib.h" ],
|
|
[ 'targets/linker.ld', "$bd/linker.ld" ],
|
|
[ 'targets/startup.s', "$bd/startup.s" ],
|
|
[ 'targets/syscalls.c', "$bd/syscalls.c" ],
|
|
[ "targets/wasm-module/$module.cpp", "$bd/wasm-module.cpp" ],
|
|
);
|
|
for my $pair (@files) {
|
|
copy( $pair->[0], $pair->[1] )
|
|
or die "failed to copy $pair->[0] -> $pair->[1]: $!";
|
|
}
|
|
}
|
|
|
|
sub compile_wasm_module {
|
|
my ( $module, $bd ) = @_;
|
|
Util::run( "$wasi_root/bin/clang", @wasi_cflags,
|
|
"targets/wasm-module/$module.cpp",
|
|
'-o', "$bd/wasm_module.wasm" );
|
|
}
|
|
|
|
sub compile_wasm_aot {
|
|
my ( $module, $bd, $target ) = @_;
|
|
my @flags = ( $target eq 'linux' ) ? @linux_wamrcflags : @cross_wamrcflags;
|
|
Util::run( 'wamrc', @flags, '-o', "$bd/wasm_module.aot",
|
|
"$bd/wasm_module.wasm" );
|
|
}
|
|
|
|
sub make_aot_array {
|
|
my ( $module, $bd ) = @_;
|
|
open( my $xxd, '-|', 'xxd', '-i', "$bd/wasm_module.aot" )
|
|
or die "failed to run xxd: $!";
|
|
my $content = do { local $/; <$xxd> };
|
|
close($xxd);
|
|
|
|
$content =
|
|
qq{__attribute__((section(".text.wamr_aot"), aligned(4096)))\n}
|
|
. $content
|
|
if $use_aot_in_text;
|
|
|
|
Util::write_file( "$bd/wasm_aot_array.c", $content );
|
|
}
|
|
|
|
sub make_interp_array {
|
|
my ( $module, $bd ) = @_;
|
|
open( my $xxd, '-|', 'xxd', '-i', "$bd/wasm_module.wasm" )
|
|
or die "Cannot run xxd: $!\n";
|
|
my $content = do { local $/; <$xxd> };
|
|
close($xxd);
|
|
Util::write_file( "$bd/wasm_interp_array.c", $content );
|
|
}
|
|
|
|
sub prepare_wasm_host {
|
|
my ( $module, $bd, $mode ) = @_;
|
|
my $template = 'targets/wasm-host/wasm_host.c';
|
|
|
|
my $mod_c = ( $module =~ s/-/_/gr );
|
|
my ( $array_file, $array_sym, $len_sym ) =
|
|
( $mode eq 'aot' )
|
|
? (
|
|
'wasm_aot_array.c',
|
|
"build_${mod_c}_wasm_module_aot",
|
|
"build_${mod_c}_wasm_module_aot_len"
|
|
)
|
|
: (
|
|
'wasm_interp_array.c',
|
|
"build_${mod_c}_wasm_module_wasm",
|
|
"build_${mod_c}_wasm_module_wasm_len"
|
|
);
|
|
|
|
my $content = Util::read_file($template);
|
|
$content =~ s/__WASM_ARRAY_FILE__/$array_file/g;
|
|
$content =~ s/__WASM_ARRAY__/$array_sym/g;
|
|
$content =~ s/__WASM_ARRAY_LEN__/$len_sym/g;
|
|
Util::write_file( "$bd/module_host.c", $content );
|
|
}
|
|
|
|
sub compile_wasm_host {
|
|
my ( $module, $bd, $target ) = @_;
|
|
if ( $target eq 'fail' ) {
|
|
Util::run(
|
|
$cross_cc, '-I./targets/wasm-host',
|
|
@cross_cflags, @host_variant_cflags,
|
|
@wamr_inc_baremetal, '-DTARGET_FAIL',
|
|
'-c', "$bd/module_host.c",
|
|
'-o', "$bd/system.o"
|
|
);
|
|
}
|
|
elsif ( $target eq 'linux' ) {
|
|
Util::run(
|
|
$linux_cc, '-I./targets/wasm-host',
|
|
@linux_cflags, @host_variant_cflags,
|
|
@wamr_inc_linux, '-DTARGET_LINUX',
|
|
'-c', "$bd/module_host.c",
|
|
'-o', "$bd/system.o"
|
|
);
|
|
}
|
|
elsif ( $target eq 'linux-baremetal' ) {
|
|
Util::run(
|
|
$cross_cc, '-I./targets/wasm-host',
|
|
@linux_baremetal_cflags, @host_variant_cflags,
|
|
@wamr_inc_baremetal, '-DTARGET_LINUX_BAREMETAL',
|
|
'-c', "$bd/module_host.c",
|
|
'-o', "$bd/system.o"
|
|
);
|
|
}
|
|
else {
|
|
die "Unknown target '$target'\n";
|
|
}
|
|
}
|
|
|
|
sub compile_c_module {
|
|
my ( $module, $bd, $target ) = @_;
|
|
my ( $cc, @flags ) =
|
|
( $target eq 'linux' )
|
|
? ( $linux_cc, @linux_cflags )
|
|
: ( $cross_cc, @cross_cflags );
|
|
Util::run( $cc, @flags, '-c', "targets/wasm-module/$module.cpp",
|
|
'-o', "$bd/c_module.o" );
|
|
}
|
|
|
|
sub compile_c_host {
|
|
my ( $module, $bd, $target ) = @_;
|
|
my ( $cc, @flags ) =
|
|
( $target eq 'linux' )
|
|
? ( $linux_cc, @linux_cflags, '-DTARGET_LINUX' )
|
|
: ( $cross_cc, @cross_cflags, '-DTARGET_FAIL' );
|
|
Util::run( $cc, @flags, '-c', 'targets/c-host/c_host.c', '-o',
|
|
"$bd/c_host.o" );
|
|
copy( 'targets/c-host/c_host.c', "$bd/module_host.c" );
|
|
}
|
|
|
|
sub compile_startup {
|
|
my ( $module, $bd, $target ) = @_;
|
|
return unless $target eq 'fail';
|
|
Util::run( $cross_cc, 'targets/startup.s', '-I./targets/wasm-host',
|
|
@cross_cflags, '-c', '-o', "$bd/startup.o" );
|
|
}
|
|
|
|
sub compile_syscalls {
|
|
my ( $module, $bd, $target ) = @_;
|
|
if ( $target eq 'fail' ) {
|
|
Util::run( $cross_cc, 'targets/syscalls.c',
|
|
'-I./targets/wasm-host', @cross_cflags,
|
|
'-c', '-o', "$bd/syscalls.o" );
|
|
}
|
|
elsif ( $target eq 'linux-baremetal' ) {
|
|
Util::run( $cross_cc, 'targets/syscalls.c', @linux_baremetal_cflags,
|
|
'-c', '-o', "$bd/syscalls.o" );
|
|
}
|
|
|
|
# Linux needs neither startup nor syscall stubs
|
|
}
|
|
|
|
sub link_wasm {
|
|
my ( $module, $bd, $target ) = @_;
|
|
if ( $target eq 'fail' ) {
|
|
Util::run(
|
|
$cross_cc, '-Wl,-T',
|
|
'targets/linker.ld', "$bd/system.o",
|
|
"$bd/startup.o", "$bd/syscalls.o",
|
|
"$bd/libiwasm.a", @cross_ldflags_base,
|
|
'-o', "$bd/system.elf"
|
|
);
|
|
}
|
|
elsif ( $target eq 'linux' ) {
|
|
Util::run( $linux_cc, "$bd/system.o", "$bd/libiwasm.a",
|
|
@linux_ldflags_base, '-o', "$bd/system.elf" );
|
|
}
|
|
elsif ( $target eq 'linux-baremetal' ) {
|
|
Util::run( $cross_cc, "$bd/system.o", "$bd/syscalls.o",
|
|
"$bd/libiwasm.a", @baremetal_ldflags_base, '-o', "$bd/system.elf" );
|
|
}
|
|
else {
|
|
die "Unknown target '$target'\n";
|
|
}
|
|
}
|
|
|
|
sub link_c {
|
|
my ( $module, $bd, $target ) = @_;
|
|
if ( $target eq 'fail' ) {
|
|
Util::run(
|
|
$cross_cc, '-Wl,-T',
|
|
'targets/linker.ld', "$bd/c_host.o",
|
|
"$bd/startup.o", "$bd/c_module.o",
|
|
@cross_ldflags_nowasm, '-o',
|
|
"$bd/system.elf"
|
|
);
|
|
}
|
|
elsif ( $target eq 'linux' ) {
|
|
Util::run( $linux_cc, "$bd/c_host.o", "$bd/c_module.o",
|
|
@linux_ldflags_nowasm, '-o', "$bd/system.elf" );
|
|
}
|
|
else {
|
|
die "C mode is not supported for target '$target'\n";
|
|
}
|
|
}
|
|
|
|
sub build_iso {
|
|
my ( $module, $bd ) = @_;
|
|
make_path("$bd/grub/boot/grub");
|
|
copy( 'targets/grub.cfg', "$bd/grub/boot/grub/grub.cfg" )
|
|
or die "failed to copy grub.cfg: $!\n";
|
|
copy( "$bd/system.elf", "$bd/grub/boot/system.elf" )
|
|
or die "failed to copy system.elf: $!\n";
|
|
Util::run( 'grub-mkrescue', '-o', "$bd/system.iso", "$bd/grub" );
|
|
}
|