Skip to content

Add cpp test, fix locale issues and fix CI issues #37

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jan 23, 2023
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
39 changes: 23 additions & 16 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
rubocop:
name: Lint (Rubocop)
runs-on: ubuntu-20.04
container: ruby:2.6
container: ruby:2.7
steps:
- name: Checkout
uses: actions/checkout@v2
Expand All @@ -30,7 +30,7 @@ jobs:
outputs:
GEM_VERSION: ${{ steps.set-metadata.outputs.GEM_VERSION }}
runs-on: ubuntu-20.04
container: ruby:2.6
container: ruby:2.7
steps:
- name: Checkout
uses: actions/checkout@v2
Expand Down Expand Up @@ -118,6 +118,14 @@ jobs:
- name: Inject V8
run: |
./libexec/inject-libv8 ${{ steps.set-metadata.outputs.NODE_VERSION }}
- name: Test V8 in C++
if: matrix.platform != 'arm64'
run: |
cd test/gtest
cmake -S . -B build
cd build
cmake --build .
./c_v8_tests
- name: Build binary gem
run: |
bundle exec rake binary
Expand Down Expand Up @@ -191,10 +199,10 @@ jobs:
run: |
case ${{ matrix.libc }} in
gnu)
echo 'ruby:2.4'
echo 'ruby:2.7'
;;
musl)
echo 'ruby:2.4-alpine'
echo 'ruby:2.7-alpine'
;;
esac | tee container_image
echo "::set-output name=image::$(cat container_image)"
Expand All @@ -203,11 +211,15 @@ jobs:
echo "::set-output name=id::$(cat container_id)"
- name: Install Alpine system dependencies
if: ${{ matrix.libc == 'musl' }}
run: docker exec -w "${PWD}" ${{ steps.container.outputs.id }} apk add --no-cache build-base linux-headers bash python3 git curl tar
run: docker exec -w "${PWD}" ${{ steps.container.outputs.id }} apk add --no-cache build-base linux-headers bash python3 git curl tar cmake
- name: Install Debian system dependencies
if: ${{ matrix.libc == 'gnu' }}
run: |
docker exec -w "${PWD}" ${{ steps.container.outputs.id }} apt-get update
docker exec -w "${PWD}" ${{ steps.container.outputs.id }} apt-get install -y cmake
- name: Install Debian cross-compiler
if: ${{ matrix.libc == 'gnu' && matrix.platform != 'amd64' }}
run: |
docker exec -w "${PWD}" ${{ steps.container.outputs.id }} apt-get update
docker exec -w "${PWD}" ${{ steps.container.outputs.id }} apt-get install -y binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- name: Checkout
uses: actions/checkout@v2
Expand Down Expand Up @@ -245,6 +257,10 @@ jobs:
- name: Inject V8
run: |
docker exec -w "${PWD}" ${{ steps.container.outputs.id }} ./libexec/inject-libv8 ${{ steps.set-metadata.outputs.NODE_VERSION }}
- name: Test V8 in C++
if: matrix.platform != 'arm64'
run: |
docker exec -w "${PWD}" ${{ steps.container.outputs.id }} bash -c "cd test/gtest && cmake -S . -B build && cd build && cmake --build . && ctest"
- name: Build binary gem
run: |
docker exec -w "${PWD}" ${{ steps.container.outputs.id }} bundle exec rake binary[${{ steps.platform.outputs.ruby_target_platform }}]
Expand All @@ -266,12 +282,6 @@ jobs:
- amd64
# other platforms would need emulation, which is way too slow
container:
- image: ruby:2.6
version: '2.6'
libc: gnu
- image: ruby:2.6-alpine
version: '2.6'
libc: musl
- image: ruby:2.7
version: '2.7'
libc: gnu
Expand Down Expand Up @@ -312,6 +322,7 @@ jobs:
run: gem install --verbose pkg/libv8-node-${{ needs.build-ruby.outputs.GEM_VERSION }}.gem
- name: Test with mini_racer
run: |
export BUNDLE_FORCE_RUBY_PLATFORM=y
git clone https://github.com/rubyjs/mini_racer.git test/mini_racer --depth 1
cd test/mini_racer
git fetch origin v0.6.3
Expand Down Expand Up @@ -364,7 +375,6 @@ jobs:
fail-fast: false
matrix:
version:
- '2.6'
- '2.7'
- '3.0'
- '3.1'
Expand All @@ -378,9 +388,6 @@ jobs:
- gnu
- musl
include:
- version: '2.6'
platform: 'arm64'
libc: 'gnu'
- version: '2.7'
platform: 'arm64'
libc: 'gnu'
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ gem: pkg/libv8-node-$(VERSION)-$(CPU)-$(OS).gem

test: test/$(CPU)-$(OS)

ctest: vendor/v8
cd test/gtest && cmake -S . -B build && cd build && cmake --build . && ctest

src/node-v$(NODE_VERSION).tar.gz:
./libexec/download-node $(NODE_VERSION)

Expand Down
8 changes: 8 additions & 0 deletions libexec/build-libv8
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,13 @@ ${CXX} -v
make BUILDTYPE="${BUILDTYPE}" config.gypi
make BUILDTYPE="${BUILDTYPE}" "out/Makefile"

# workaround for node specifying `-msign-return-address=all` in ALL `CFLAGS` for aarch64 builds
# (if the host isn't also aarch64, this flag causes a compiler error)

# shellcheck disable=SC2154 # these variables are defined by `eval`ing the output of the platform script above
if [ "$host_platform" != "$target_platform" ] && [ "${target_platform%%-*}" = "aarch64" ]; then
find . -iname "*.host.mk" -exec sed -i '/-msign-return-address/d' {} ';'
fi

export PATH="${PWD}/out/tools/bin:${PATH}"
make -j"${NJOBS}" -C out BUILDTYPE="${BUILDTYPE}" V=0
9 changes: 4 additions & 5 deletions libexec/build-monolith
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,20 @@ platform=$(uname)
rm -f "${LIBV8_MONOLITH}"
case "${platform}" in
"SunOS")
/usr/xpg4/bin/find . -path "./torque_*/**/*.o" -or -path "./v8*/**/*.o" -or -path "./icu*/**/*.o" | sort | uniq | while read -r obj; do
/usr/xpg4/bin/find . '(' '!' -path './icutools/deps/icu-small/source/stubdata/stubdata.o' ')' -and '(' -path "./torque_*/**/*.o" -or -path "./v8*/**/*.o" -or -path "./icu*/**/*.o" ')' | sort | uniq | while read -r obj; do
ar cqS "${LIBV8_MONOLITH}" "${obj}"
done
ranlib "${LIBV8_MONOLITH}"
;;
"Darwin")
/usr/bin/find . -path "./torque_*/**/*.o" -or -path "./v8*/**/*.o" -or -path "./icu*/**/*.o" | sort | uniq | while read -r obj; do
/usr/bin/find . '(' '!' -path './icutools/deps/icu-small/source/stubdata/stubdata.o' ')' -and '(' -path "./torque_*/**/*.o" -or -path "./v8*/**/*.o" -or -path "./icu*/**/*.o" ')' | sort | uniq | while read -r obj; do
/usr/bin/ar -cqS "${LIBV8_MONOLITH}" "${obj}"
done
/usr/bin/ranlib "${LIBV8_MONOLITH}"
;;
"Linux")
find . -path "./torque_*/**/*.o" -or -path "./v8*/**/*.o" -or -path "./icu*/**/*.o" | sort | uniq | while read -r obj; do
ar -cq "${LIBV8_MONOLITH}" "${obj}"
done
find . '(' '!' -path './icutools/deps/icu-small/source/stubdata/stubdata.o' ')' -and '(' -path "./torque_*/**/*.o" -or -path "./v8*/**/*.o" -or -path "./icu*/**/*.o" ')' | sort | uniq | xargs ar -cqSP "${LIBV8_MONOLITH}"
ar -sP "${LIBV8_MONOLITH}"
;;
*)
echo "Unsupported platform: ${platform}"
Expand Down
31 changes: 29 additions & 2 deletions libexec/inject-libv8
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,35 @@ for lib in libv8_monolith.a; do
mkdir -p "${dir}"
rm -f "${dir}/${lib}"

echo "${BASEDIR}/out/${BUILDTYPE}/${lib} -> ${dir}/${lib}"
"${STRIP}" -S -x -o "${dir}/${lib}" "${lib}"
if [ "$STRIP_NEEDS_EXTRACT" = "y" ]; then
# manual extract/strip objects/build archive sequence
# because `strip` can't deal with these
# (presumably due to that folder issue mentioned below)
(
tmpdir="$(mktemp -d)"
trap 'rm -r "$tmpdir"' EXIT
mkdir "$tmpdir/stage"
cd "$tmpdir/stage"

# create folders named in `ar` archive (`ar -x` fails to create these)
"$AR" "$ARLISTFLAGS" "$BASEDIR/out/$BUILDTYPE/$lib" | while read -r path; do
dirname "$path"
done | uniq | xargs mkdir -p
"$AR" "$AREXTRACTFLAGS" "$BASEDIR/out/${BUILDTYPE}/$lib"

# strip all objects
"$FIND" -type f -exec "$STRIP" -Sx {} +

# rebuild the archive
"$FIND" -type f -exec "$AR" "$ARCOLLECTFLAGS" "../$lib" {} +
$ARBUILDSYMBOLS "../$lib"
mv "../$lib" "$dir/$lib"
)
echo "${BASEDIR}/out/${BUILDTYPE}/${lib} -> ${dir}/${lib}"
else
echo "${BASEDIR}/out/${BUILDTYPE}/${lib} -> ${dir}/${lib}"
"${STRIP}" -S -x -o "${dir}/${lib}" "${lib}"
fi
done

mkdir -p "${top}/ext/libv8-node"
Expand Down
21 changes: 21 additions & 0 deletions libexec/platform
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ elif command -v cc >/dev/null 2>&1; then
fi

STRIP="${STRIP:-strip}"
AR="${AR:-ar}"
AREXTRACTFLAGS="${AREXTRACTFLAGS:--x}"
ARLISTFLAGS="${ARLISTFLAGS:--t}"
ARCOLLECTFLAGS="${ARCOLLECTFLAGS:-cqS}"
# this is the command to build the symbol table in an ar archive.
ARBUILDSYMBOLS="${ARBUILDSYMBOLS:-ranlib}"
FIND="${FIND:-find}"
STRIP_NEEDS_EXTRACT="${STRIP_NEEDS_EXTRACT:-n}"

triple=$(${CC} -dumpmachine)
host_platform="${triple}"
Expand Down Expand Up @@ -63,6 +71,11 @@ case "${host_platform}" in
CXX="${CXX:-/opt/local/gcc7/bin/g++}"
STRIP="gstrip"
;;
*linux*)
STRIP_NEEDS_EXTRACT="y"
ARCOLLECTFLAGS="-cqSP"
ARBUILDSYMBOLS="${AR} -sP"
;;
esac

if [ "${host_platform}" != "${target_platform}" ]; then
Expand Down Expand Up @@ -146,6 +159,14 @@ export CC='${CC}'
export CXX='${CXX}'
host_platform='${host_platform}'
target_platform='${target_platform}'
STRIP='$STRIP'
AR='$AR'
AREXTRACTFLAGS='$AREXTRACTFLAGS'
ARLISTFLAGS='$ARLISTFLAGS'
ARCOLLECTFLAGS='$ARCOLLECTFLAGS'
ARBUILDSYMBOLS='$ARBUILDSYMBOLS'
FIND='$FIND'
STRIP_NEEDS_EXTRACT='$STRIP_NEEDS_EXTRACT'
EOF

if [ -n "${CC_host:-}" ]; then cat <<EOF; fi
Expand Down
14 changes: 14 additions & 0 deletions test/gtest/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
build
lib
bin
51 changes: 51 additions & 0 deletions test/gtest/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
cmake_minimum_required(VERSION 3.14)
project(gtest)

# GoogleTest requires at least C++14
set(CMAKE_CXX_STANDARD 14)

include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

enable_testing()

include_directories(${CMAKE_SOURCE_DIR}/../../vendor/v8/include/)

add_executable(
c_v8_tests
c_v8_tests.cc
)
target_link_libraries(
c_v8_tests
GTest::gtest_main
)

string(TOLOWER ${CMAKE_SYSTEM_NAME} system_name)
string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} system_arch)

set(vendor_arch "${system_arch}-${system_name}")

if(${system_name} STREQUAL "linux")
try_compile(is_glibc ${CMAKE_BINARY_DIR}/check_glibc ${CMAKE_SOURCE_DIR}/check_glibc.c)
if(NOT is_glibc)
# assume non-glibc is musl-libc
string(APPEND vendor_arch "-musl")
endif()
endif()

message(STATUS "Detected vendor architecture directory: ${vendor_arch}")

# TODO?: Detect and support ruby-arch builds?
target_link_libraries(c_v8_tests ${CMAKE_SOURCE_DIR}/../../vendor/v8/${vendor_arch}/libv8/obj/libv8_monolith.a)

# This has to be after the v8 monolith for some build setups.
target_link_libraries(c_v8_tests dl)

include(GoogleTest)
gtest_discover_tests(c_v8_tests)
53 changes: 53 additions & 0 deletions test/gtest/Framework.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma once

#include <v8.h>
#include <libplatform/libplatform.h>
#include <functional>

struct Framework {
typedef std::function<void()> basic_main;
typedef std::function<void(v8::Isolate*)> iso_main;
typedef std::function<void(v8::Local<v8::Context>&)> ctx_main;

inline static void run(basic_main main) {
std::shared_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
main();

v8::V8::Dispose();
v8::V8::ShutdownPlatform();
}

inline static void runWithIsolateRaw(iso_main main) {
Framework::run([main]() -> void {
v8::Isolate::CreateParams p;
p.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8::Isolate* iso = v8::Isolate::New(p);

main(iso);

iso->Dispose();
delete p.array_buffer_allocator;
});
}

inline static void runWithIsolate(iso_main main) {
Framework::runWithIsolateRaw([main](v8::Isolate* iso) -> void {
v8::Locker lock { iso };
v8::Isolate::Scope iScope { iso };
v8::HandleScope hScope { iso };

main(iso);
});
}

inline static void runWithContext(ctx_main main) {
Framework::runWithIsolate([main](v8::Isolate* iso) -> void {
v8::Local<v8::Context> ctx = v8::Context::New(iso);
v8::Context::Scope cScope { ctx };

main(ctx);
});
}
};
18 changes: 18 additions & 0 deletions test/gtest/c_v8_tests.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <gtest/gtest.h>

#include <v8.h>
#include <libplatform/libplatform.h>

#include "Framework.h"

// Demonstrate some basic assertions.
TEST(FRLocaleTest, LocaleTests) {
Framework::runWithContext([](v8::Local<v8::Context>& ctx) -> void {
v8::Local<v8::Script> script = v8::Script::Compile(ctx, v8::String::NewFromUtf8Literal(ctx->GetIsolate(), "new Date('April 28 2021').toLocaleDateString('fr-FR');")).ToLocalChecked();
v8::Local<v8::Value> result = script->Run(ctx).ToLocalChecked();
v8::Local<v8::String> resultStr = result->ToString(ctx).ToLocalChecked();
v8::String::Utf8Value resultUTF8(ctx->GetIsolate(), resultStr);

EXPECT_STREQ(*resultUTF8, "28/04/2021");
});
}
10 changes: 10 additions & 0 deletions test/gtest/check_glibc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#warning "This is not a source file -- it exists purely to allow CMake to distinguish between glibc and musl-libc. If you see this message, you are likely doing something incorrectly."

#include <stdlib.h>

#ifndef __GLIBC__
#error "__GLIBC__ is undef -- not glibc!"
#endif

int main() { }