Merge pull request #4378 from talregev/TalR_boinc_wasm

[Webassembly] Compile boinc client as webassembly
This commit is contained in:
Vitalii Koshura 2022-06-09 16:12:17 +02:00 committed by GitHub
commit 779b451815
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 297 additions and 3 deletions

85
.github/workflows/wasm.yml vendored Normal file
View File

@ -0,0 +1,85 @@
name: Webassembly
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
schedule:
- cron: '10 12 * * 0'
jobs:
build:
name: ${{ matrix.type }}-build
runs-on: ubuntu-latest
strategy:
matrix:
type: [client]
fail-fast: false
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 2
- name: Install dependencies
run: |
sudo apt-get -qq update
sudo apt-get install -y p7zip-full zip
- name: Cache dependencies
uses: actions/cache@v2.1.3
with:
path: |
3rdParty/buildCache
!3rdParty/buildCache/wasm/vcpkgcache/
key: wasm-${{ matrix.type }}-${{ hashFiles('wasm/*.sh') }}
restore-keys: wasm-${{ matrix.type }}-
- name: Check if build is running from origin repo
if: ${{ success() && env.AWS_ACCESS_KEY_ID != 0 && env.AWS_SECRET_ACCESS_KEY != 0 }}
run: |
echo "VCPKG_BINARY_SOURCES=clear;x-aws,s3://vcpkg.cache.boinc/,readwrite" >> $GITHUB_ENV
- name: Check if build is running from fork
if: ${{ success() && (env.AWS_ACCESS_KEY_ID == 0 || env.AWS_SECRET_ACCESS_KEY == 0) }}
run: |
echo "VCPKG_BINARY_SOURCES=clear;x-aws-config,no-sign-request;x-aws,s3://vcpkg.cache.boinc/,read" >> $GITHUB_ENV
- name: Automake
if: success()
run: ./_autosetup
- name: Configure client as webassembly
if: success() && matrix.type == 'client'
run: wasm/ci_configure_client.sh
- name: Make
if: success()
run: wasm/ci_make.sh
- name: Prepare logs on failure
if: ${{ failure() }}
uses: edgarrc/action-7z@v1.0.4
with:
args: 7z a -t7z -mx=9 deploy/logs.7z config.log -r0 3rdParty/wasm/vcpkg/buildtrees/*.log
- name: Upload logs on failure
if: ${{ failure() }}
uses: actions/upload-artifact@v2
with:
name: wasm_logs_${{ matrix.type }}_${{ github.event.pull_request.head.sha }}
path: deploy/logs.7z
- name: Prepare artifacts for deploy
if: success() && ! contains(matrix.type, 'libs')
env:
PULL_REQUEST: ${{ github.event.number }}
PULL_REQUEST_SHA: ${{ github.event.pull_request.head.sha }}
run: python ./deploy/prepare_deployment.py wasm_${{ matrix.type }}
- name: Upload artifacts
uses: actions/upload-artifact@v2
if: ${{ ! contains(matrix.type, 'libs') }}
with:
name: wasm_${{ matrix.type }}_${{ github.event.pull_request.head.sha }}
path: deploy/wasm_${{ matrix.type }}.7z

8
.gitignore vendored
View File

@ -74,6 +74,7 @@ compile
config.guess
config.sub
configure
configure~
depcomp
install-sh
ltmain.sh
@ -227,3 +228,10 @@ vda/vdad
build/
build-*/
# WASM
*.wasm
a.out.js
boinc.js
boinc_client.js
boinccmd.js
switcher.js

View File

@ -0,0 +1,13 @@
{
"name": "boinc-client",
"version-string": "7.21.0",
"dependencies":
[
{
"name": "curl",
"features": ["openssl"],
"default-features": false
},
"rappture"
]
}

View File

@ -0,0 +1,25 @@
set(VCPKG_BUILD_TYPE release)
set(VCPKG_ENV_PASSTHROUGH_UNTRACKED EMSCRIPTEN_ROOT EMSDK PATH)
if(NOT DEFINED ENV{EMSCRIPTEN_ROOT})
find_path(EMSCRIPTEN_ROOT "emcc")
else()
set(EMSCRIPTEN_ROOT "$ENV{EMSCRIPTEN_ROOT}")
endif()
if(NOT EMSCRIPTEN_ROOT)
if(NOT DEFINED ENV{EMSDK})
message(FATAL_ERROR "The emcc compiler not found in PATH")
endif()
set(EMSCRIPTEN_ROOT "$ENV{EMSDK}/upstream/emscripten")
endif()
if(NOT EXISTS "${EMSCRIPTEN_ROOT}/cmake/Modules/Platform/Emscripten.cmake")
message(FATAL_ERROR "Emscripten.cmake toolchain file not found")
endif()
set(VCPKG_TARGET_ARCHITECTURE wasm32)
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CMAKE_SYSTEM_NAME Emscripten)
set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${EMSCRIPTEN_ROOT}/cmake/Modules/Platform/Emscripten.cmake")

View File

@ -181,6 +181,16 @@ extern "C" {
#define LINUX_LIKE_SYSTEM 1
#endif
#if WASM
#include <emscripten.h>
#endif
#if WASM
EM_JS(FILE*, popen, (const char* command, const char* mode), {
//TODO: add javascript code
});
#endif
// Returns the offset between LOCAL STANDARD TIME and UTC.
// LOCAL_STANDARD_TIME = UTC_TIME + get_timezone().
//
@ -1238,6 +1248,9 @@ int HOST_INFO::get_cpu_info() {
strlcpy( p_model, cpuInfo.name.fromID, sizeof(p_model));
#elif defined(__HAIKU__)
get_cpu_info_haiku(*this);
#elif WASM
strlcpy( p_vendor, "WASM", sizeof(p_vendor));
strlcpy( p_model, "WASM", sizeof(p_model));
#elif HAVE_SYS_SYSCTL_H
int mib[2];
size_t len;

View File

@ -51,6 +51,16 @@ using std::string;
#define safe_strcat(x, y) strlcat(x, y, sizeof(x))
#define LINUX_LIKE_SYSTEM (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(__HAIKU__)
#if WASM
#include <emscripten.h>
#endif
#if WASM
EM_JS(FILE*, popen, (const char* command, const char* mode), {
//TODO: add javascript code
});
#endif
enum LINUX_OS_INFO_PARSER {
lsbrelease,
osrelease,

View File

@ -149,6 +149,12 @@ AC_ARG_ENABLE(apps-gui,
[enable_apps_gui=${enableval}],
[enable_apps_gui=no])
AC_ARG_ENABLE(wasm,
AS_HELP_STRING([--enable-wasm],
[enable building the boinc wasm]),
[enable_wasm=${enableval}],
[enable_wasm=no])
AC_ARG_ENABLE(unit-tests,
AS_HELP_STRING([--enable-unit-tests],
[enable building the boinc unit tests]),
@ -372,6 +378,10 @@ dnl the manpages only if docbook2x-man is available.
AC_PATH_PROG(DOCBOOK2X_MAN, docbook2x-man)
AM_CONDITIONAL(HAVE_DOCBOOK2X_MAN, [test -n "${DOCBOOK2X_MAN}"])
if test "${enable_wasm}" = yes ; then
EXEEXT=.js
fi
AC_SUBST([CLIENT_BIN_FILENAME],[boinc${EXEEXT}])
AC_SUBST([CLIENT_CMD_BIN_FILENAME],[boinccmd${EXEEXT}])
AC_SUBST([CLIENT_GUI_BIN_FILENAME],[boincmgr${EXEEXT}])
@ -707,7 +717,11 @@ AC_TYPE_SIGNAL
if test "${isWIN32}" = "yes" ; then
AC_CHECK_HEADERS(winsock2.h winsock.h windows.h ws2tcpip.h winternl.h crtdbg.h)
fi
AC_CHECK_HEADERS([sys/types.h sys/un.h arpa/inet.h dirent.h grp.h fcntl.h inttypes.h stdint.h memory.h netdb.h netinet/in.h netinet/tcp.h netinet/ether.h net/if.h net/if_arp.h signal.h strings.h sys/auxv.h sys/file.h sys/fcntl.h sys/ipc.h sys/ioctl.h sys/msg.h sys/param.h sys/resource.h sys/select.h sys/sem.h sys/shm.h sys/sockio.h sys/socket.h sys/stat.h sys/statvfs.h sys/statfs.h sys/systeminfo.h sys/time.h sys/types.h sys/utsname.h sys/vmmeter.h sys/wait.h unistd.h utmp.h errno.h procfs.h ieeefp.h setjmp.h float.h sal.h execinfo.h xlocale.h])
AC_CHECK_HEADERS(sys/types.h sys/un.h arpa/inet.h dirent.h grp.h fcntl.h inttypes.h stdint.h memory.h netdb.h netinet/in.h netinet/tcp.h netinet/ether.h net/if.h net/if_arp.h signal.h strings.h sys/auxv.h sys/file.h sys/fcntl.h sys/ipc.h sys/ioctl.h sys/msg.h sys/param.h sys/resource.h sys/select.h sys/sem.h sys/sockio.h sys/socket.h sys/stat.h sys/statvfs.h sys/statfs.h sys/systeminfo.h sys/time.h sys/types.h sys/utsname.h sys/vmmeter.h sys/wait.h unistd.h utmp.h errno.h procfs.h ieeefp.h setjmp.h float.h sal.h execinfo.h xlocale.h)
if test "${enable_wasm}" != yes ; then
AC_CHECK_HEADERS(sys/shm.h)
fi
save_cxxflags="${CXXFLAGS}"
save_cppflags="${CPPFLAGS}"
@ -1103,10 +1117,16 @@ AM_CONDITIONAL(OS_OS2, [echo $host_os | grep '^os2' > /dev/null])
AM_CONDITIONAL(OS_ARM_LINUX, [echo $host_alias | grep '^arm-linux' > /dev/null])
AM_CONDITIONAL(OS_ARMV6_LINUX, [echo $host_alias | grep '^armv6-linux' > /dev/null])
AM_CONDITIONAL(ANDROID, [test x"${ANDROID}" = xyes])
AM_CONDITIONAL(BUILD_WITH_VCPKG, [test "${enable_apps_vcpkg}" = yes])
AM_CONDITIONAL(BUILD_WITH_VBOX, [test "${enable_apps_vbox}" = yes])
AM_CONDITIONAL(BUILD_WITH_MINGW, [test "${enable_apps_mingw}" = yes])
AM_CONDITIONAL(BUILD_WITH_GUI, [test "${enable_apps_gui}" = yes])
AM_CONDITIONAL(BUILD_WITH_WASM, [test "${enable_wasm}" = yes])
if test "${enable_wasm}" = yes ; then
AC_DEFINE([WASM], [1], [build boinc wasm])
fi
dnl Whether to build fcgi components
AM_CONDITIONAL(ENABLE_FCGI,[test "${enable_fcgi}" = yes])

View File

@ -184,6 +184,12 @@ windows_manager_list = [
'./win_build/Build/ARM64/Release/boincmgr.exe'
]
wasm_client_list = [
'./client/boinc_client.wasm',
'./client/boinc.js',
'./samples/wasm/index.html',
]
def prepare_7z_archive(archive_name, target_directory, files_list):
os.makedirs(target_directory, exist_ok=True)
archive_path = os.path.join(target_directory, archive_name + '.7z')
@ -246,6 +252,9 @@ def prepare_win_client(target_directory):
def prepare_win_manager(target_directory):
prepare_7z_archive('win_manager', target_directory, windows_manager_list)
def prepare_wasm_client(target_directory):
prepare_7z_archive('wasm_client', target_directory, wasm_client_list)
boinc_types = {
'linux_client': prepare_linux_client,
'linux_client-vcpkg': prepare_linux_client_vcpkg,
@ -262,14 +271,14 @@ boinc_types = {
'android_apps-vcpkg': prepare_android_apps_vcpkg,
'win_apps': prepare_win_apps,
'win_client': prepare_win_client,
'win_manager': prepare_win_manager
'win_manager': prepare_win_manager,
'wasm_client': prepare_wasm_client
}
if (len(sys.argv) != 2):
help()
sys.exit(1)
boinc_type = sys.argv[1]
target_dir = 'deploy'

View File

@ -131,6 +131,9 @@ mac_headers=
endif
endif
if BUILD_WITH_WASM
generic_sources += wasm.cpp
endif
if INSTALL_HEADERS
pkginclude_HEADERS = \

27
lib/wasm.cpp Normal file
View File

@ -0,0 +1,27 @@
// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2022 University of California
//
// BOINC is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// BOINC is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
#include <sys/ipc.h>
#include <sys/stat.h>
key_t ftok(const char *path, int id)
{
struct stat st;
if (stat(path, &st) < 0) return -1;
return ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) | ((id & 0xff) << 24));
}

6
samples/wasm/index.html Normal file
View File

@ -0,0 +1,6 @@
<html>
<body>
<h1>Boinc</h1>
<script src="boinc.js"></script>
</body>
</html>

20
wasm/ci_configure_client.sh Executable file
View File

@ -0,0 +1,20 @@
#!/bin/bash
set -e
if [ ! -d "wasm" ]; then
echo "start this script in the source root directory"
exit 1
fi
CACHE_DIR="$PWD/3rdParty/buildCache/wasm"
BUILD_DIR="$PWD/3rdParty/wasm"
VCPKG_ROOT="$BUILD_DIR/vcpkg"
EMSDK_ROOT="$BUILD_DIR/emsdk"
export VCPKG_DIR="$VCPKG_ROOT/installed/wasm32-emscripten"
wasm/update_emsdk.sh
source $EMSDK_ROOT/emsdk_env.sh
wasm/update_emsdk_vcpkg.sh
export _libcurl_pc="$VCPKG_DIR/lib/pkgconfig/libcurl.pc"
emconfigure ./configure --enable-wasm --enable-vcpkg --with-libcurl=$VCPKG_DIR --with-ssl=$VCPKG_DIR --disable-server --enable-client --disable-manager

13
wasm/ci_make.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
set -e
if [ ! -d "wasm" ]; then
echo "start this script in the source root directory"
exit 1
fi
BUILD_DIR="$PWD/3rdParty/wasm"
EMSDK_ROOT="$BUILD_DIR/emsdk"
source $EMSDK_ROOT/emsdk_env.sh
emmake make

21
wasm/update_emsdk.sh Executable file
View File

@ -0,0 +1,21 @@
#!/bin/sh
set -e
if [ ! -d "wasm" ]; then
echo "start this script in the source root directory"
exit 1
fi
CACHE_DIR="$PWD/3rdParty/buildCache/wasm"
BUILD_DIR="$PWD/3rdParty/wasm"
EMSDK_ROOT="$BUILD_DIR/emsdk"
if [ ! -d $EMSDK_ROOT ]; then
mkdir -p $BUILD_DIR
git -C $BUILD_DIR clone https://github.com/emscripten-core/emsdk
fi
git -C $EMSDK_ROOT pull
$EMSDK_ROOT/emsdk install latest
$EMSDK_ROOT/emsdk activate latest

21
wasm/update_emsdk_vcpkg.sh Executable file
View File

@ -0,0 +1,21 @@
#!/bin/sh
set -e
if [ ! -d "wasm" ]; then
echo "start this script in the source root directory"
exit 1
fi
BUILD_DIR="$PWD/3rdParty/wasm"
VCPKG_PORTS="$PWD/3rdParty/vcpkg_ports"
VCPKG_ROOT="$BUILD_DIR/vcpkg"
if [ ! -d $VCPKG_ROOT ]; then
mkdir -p $BUILD_DIR
git -C $BUILD_DIR clone https://github.com/microsoft/vcpkg
fi
git -C $VCPKG_ROOT pull
$VCPKG_ROOT/bootstrap-vcpkg.sh
$VCPKG_ROOT/vcpkg install --x-manifest-root=3rdParty/vcpkg_ports/configs/client/wasm --x-install-root=$VCPKG_ROOT/installed/ --overlay-ports=$VCPKG_PORTS/ports --overlay-triplets=$VCPKG_PORTS/triplets/ci --triplet=wasm32-emscripten --clean-after-build