diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2a5b8cd..d1a8d55 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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 @@ -25,13 +25,27 @@ jobs: run: apt-get update && apt-get install -y shellcheck - name: Shellcheck run: shellcheck libexec/* + compile-truffleruby: + name: Compile on truffleruby + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v3 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: truffleruby + bundler-cache: true + - run: bundle exec rake compile build-ruby: name: Build (ruby) outputs: GEM_VERSION: ${{ steps.set-metadata.outputs.GEM_VERSION }} runs-on: ubuntu-20.04 - container: ruby:2.6 + container: ruby:2.7 steps: + - name: Update Rubygems and Bundler + run: | + gem update --system 3.3.26 + gem install bundler -v '~> 2.3.26' - name: Checkout uses: actions/checkout@v2 - name: Bundle @@ -73,11 +87,14 @@ jobs: matrix: platform: - x86_64 - # arm64 + - arm64 name: Build (darwin) outputs: GEM_VERSION: ${{ steps.set-metadata.outputs.GEM_VERSION }} - runs-on: macos-10.15 + runs-on: macos-11 + env: + TARGET_PLATFORM: ${{ matrix.platform }}-darwin + RUBY_TARGET_PLATFORM: ${{ matrix.platform }}-darwin steps: - name: Checkout uses: actions/checkout@v2 @@ -115,6 +132,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 @@ -188,10 +213,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)" @@ -200,12 +225,20 @@ 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 python2 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: Update Rubygems and Bundler + run: | + docker exec -w "${PWD}" ${{ steps.container.outputs.id }} gem update --system 3.3.26 + docker exec -w "${PWD}" ${{ steps.container.outputs.id }} gem install bundler -v '~> 2.3.26' - name: Checkout uses: actions/checkout@v2 - name: Bundle @@ -242,6 +275,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 }}] @@ -256,11 +293,49 @@ jobs: name: gem-${{ steps.set-metadata.outputs.GEM_VERSION }}-${{ steps.platform.outputs.ruby_target_platform }} path: pkg test-ruby: - name: Test (ruby) + strategy: + fail-fast: false + matrix: + platform: + - amd64 + # other platforms would need emulation, which is way too slow + container: + - image: ruby:2.7 + version: '2.7' + libc: gnu + - image: ruby:2.7-alpine + version: '2.7' + libc: musl + - image: ruby:3.0 + version: '3.0' + libc: gnu + - image: ruby:3.0-alpine + version: '3.0' + libc: musl + - image: ruby:3.1 + version: '3.1' + libc: gnu + - image: ruby:3.1-alpine + version: '3.1' + libc: musl + - image: ruby:3.2 + version: '3.2' + libc: gnu + - image: ruby:3.2-alpine + version: '3.2' + libc: musl + name: Test (ruby) (${{ matrix.container.version }}, ${{ matrix.platform }}, ${{ matrix.container.libc }}) needs: build-ruby runs-on: ubuntu-20.04 - container: ruby:2.5 + container: ${{ matrix.container.image }} steps: + - name: Install Alpine system dependencies + if: ${{ matrix.container.libc == 'musl' }} + run: apk add --no-cache build-base linux-headers bash python3 git curl tar + - name: Update Rubygems and Bundler + run: | + gem update --system 3.3.26 + gem install bundler -v '~> 2.3.26' - name: Set metadata id: set-metadata run: | @@ -275,13 +350,15 @@ 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 refs/pull/210/head - git checkout FETCH_HEAD + git fetch origin v0.6.3 + git checkout -f FETCH_HEAD git reset --hard git clean -f -d -x ruby -i -ne '$_ =~ /^\s+LIBV8_NODE_VERSION/ ? print(" LIBV8_NODE_VERSION = \"${{ needs.build-ruby.outputs.GEM_VERSION }}\"\n") : print' lib/mini_racer/version.rb + ruby -i -ne '$_ =~ /spec.required_ruby_version/ ? "" : print' mini_racer.gemspec bundle install bundle exec rake compile bundle exec rake test @@ -294,7 +371,7 @@ jobs: # arm64 name: Test (darwin) needs: build-darwin - runs-on: macos-10.15 + runs-on: macos-11 steps: - name: Set metadata id: set-metadata @@ -312,11 +389,12 @@ jobs: run: | git clone https://github.com/rubyjs/mini_racer.git test/mini_racer --depth 1 cd test/mini_racer - git fetch origin refs/pull/210/head - git checkout FETCH_HEAD + git fetch origin v0.6.3 + git checkout -f FETCH_HEAD git reset --hard git clean -f -d -x ruby -i -ne '$_ =~ /^\s+LIBV8_NODE_VERSION/ ? print(" LIBV8_NODE_VERSION = \"${{ needs.build-darwin.outputs.GEM_VERSION }}\"\n") : print' lib/mini_racer/version.rb + ruby -i -ne '$_ =~ /spec.required_ruby_version/ ? "" : print' mini_racer.gemspec bundle install bundle exec rake compile bundle exec rake test @@ -325,10 +403,10 @@ jobs: fail-fast: false matrix: version: - - '2.5' - - '2.6' - '2.7' - '3.0' + - '3.1' + - '3.2' platform: - amd64 # arm64 @@ -339,16 +417,16 @@ jobs: - gnu - musl include: - - version: '2.5' + - version: '2.7' platform: 'arm64' libc: 'gnu' - - version: '2.6' + - version: '3.0' platform: 'arm64' libc: 'gnu' - - version: '2.7' + - version: '3.1' platform: 'arm64' libc: 'gnu' - - version: '3.0' + - version: '3.2' platform: 'arm64' libc: 'gnu' name: Test (linux) @@ -379,10 +457,14 @@ jobs: - name: Install Alpine system dependencies if: ${{ matrix.libc == 'musl' }} run: docker exec -w "${PWD}" ${{ steps.container.outputs.id }} apk add --no-cache build-base git libstdc++ + - name: Update Rubygems and Bundler + run: | + docker exec -w "${PWD}" ${{ steps.container.outputs.id }} gem update --system 3.3.26 + docker exec -w "${PWD}" ${{ steps.container.outputs.id }} gem install bundler -v '~> 2.3.26' - name: Set metadata id: set-metadata run: | - docker exec -w "${PWD}" ${{ steps.container.outputs.id }} ruby -e 'puts Gem.platforms.last.to_s' | tee gem_platform + docker exec -w "${PWD}" ${{ steps.container.outputs.id }} ruby -e 'puts Gem::Platform.local.tap { |p| RUBY_PLATFORM =~ /musl/ && p.version.nil? and p.instance_eval { @version = "musl" } }.to_s' | tee gem_platform echo "::set-output name=GEM_PLATFORM::$(cat gem_platform)" - name: Download a single artifact uses: actions/download-artifact@v2 @@ -395,11 +477,12 @@ jobs: run: | git clone https://github.com/rubyjs/mini_racer.git test/mini_racer --depth 1 cd test/mini_racer - git fetch origin refs/pull/210/head - git checkout FETCH_HEAD + git fetch origin v0.6.3 + git checkout -f FETCH_HEAD git reset --hard git clean -f -d -x ruby -i -ne '$_ =~ /^\s+LIBV8_NODE_VERSION/ ? print(" LIBV8_NODE_VERSION = \"${{ needs.build-linux.outputs.GEM_VERSION }}\"\n") : print' lib/mini_racer/version.rb + ruby -i -ne '$_ =~ /spec.required_ruby_version/ ? "" : print' mini_racer.gemspec docker exec -w "${PWD}" ${{ steps.container.outputs.id }} bundle install docker exec -w "${PWD}" ${{ steps.container.outputs.id }} bundle exec rake compile docker exec -w "${PWD}" ${{ steps.container.outputs.id }} bundle exec rake test diff --git a/.gitignore b/.gitignore index 2844876..363d565 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ Makefile /ext/libv8-node/.location.yml /test/mini_racer +/test/bundle *.nix *.vim .envrc diff --git a/.rubocop.yml b/.rubocop.yml index a3ec089..e57f216 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,9 +1,12 @@ AllCops: + SuggestExtensions: false + NewCops: disable TargetRubyVersion: 2.0 Exclude: - src/**/* - pkg/**/* - vendor/**/* + - test/**/* Naming/FileName: Exclude: @@ -26,3 +29,6 @@ Style/WordArray: Style/PerlBackrefs: Enabled: false + +Gemspec/RequiredRubyVersion: + Enabled: false diff --git a/Dockerfile b/Dockerfile index b2f7a29..293af83 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,20 +1,26 @@ -ARG RUBY_VERSION=2.4 +ARG RUBY_VERSION=2.7 FROM ruby:${RUBY_VERSION} -RUN test ! -f /etc/alpine-release || apk add --no-cache build-base bash python2 python3 git curl tar +RUN test ! -f /etc/alpine-release || apk add --no-cache build-base bash python3 git curl tar ccache +RUN test -f /etc/alpine-release || (apt-get update && apt-get install -y ccache) +ENV CCACHE_DIR=/ccache + +RUN gem update --system 3.3.26 && gem install bundler -v '~> 2.3.26' RUN mkdir -p /code WORKDIR /code -ARG NODE_VERSION=16.10.0 +ARG NODE_VERSION=16.19.0 +COPY sums/v${NODE_VERSION}.sum /code/sums/ COPY libexec/download-node /code/libexec/ RUN ./libexec/download-node ${NODE_VERSION} COPY libexec/extract-node /code/libexec/ COPY patch/* /code/patch/ RUN ./libexec/extract-node ${NODE_VERSION} +COPY libexec/platform /code/libexec/ COPY libexec/build-libv8 /code/libexec/ -RUN ./libexec/build-libv8 ${NODE_VERSION} +RUN --mount=type=cache,id=ccache,target=/ccache/ ./libexec/build-libv8 ${NODE_VERSION} COPY libexec/build-monolith /code/libexec/ RUN ./libexec/build-monolith ${NODE_VERSION} COPY libexec/inject-libv8 /code/libexec/ diff --git a/Makefile b/Makefile index 29338e0..3779cdb 100644 --- a/Makefile +++ b/Makefile @@ -1,45 +1,50 @@ PWD := $(shell pwd) +OS := $(shell uname -s | tr '[A-Z]' '[a-z]') +CPU := $(shell uname -m) VERSION := $(shell ./libexec/metadata version) NODE_VERSION := $(shell ./libexec/metadata node_version) +RUBY_VERSION = $(shell ruby -e 'puts RUBY_VERSION.gsub(/\d+$$/, "0")') -all: +vars: + @echo $(PWD) + @echo $(OS) $(CPU) + @echo $(VERSION) $(NODE_VERSION) + @echo $(RUBY_VERSION) -pkg/libv8-node-$(VERSION)-x86_64-linux.gem: - docker build --platform linux/amd64 --build-arg RUBY_VERSION=2.4 --progress plain -t libv8-node:gnu . - docker run --platform linux/amd64 --rm -it -v "$(PWD)/pkg":/pkg libv8-node:gnu cp $@ /pkg/ +all: gem test -pkg/libv8-node-$(VERSION)-x86_64-linux-musl.gem: - docker build --platform linux/amd64 --build-arg RUBY_VERSION=2.4-alpine --progress plain -t libv8-node:musl . - docker run --platform linux/amd64 --rm -it -v "$(PWD)/pkg":/pkg libv8-node:musl cp $@ /pkg/ +build: src/node-v$(NODE_VERSION)/out/Release/node -pkg/libv8-node-$(VERSION)-aarch64-linux.gem: - docker build --platform linux/arm64 --build-arg RUBY_VERSION=2.4 --progress plain -t libv8-node:gnu . - docker run --platform linux/arm64 --rm -it -v "$(PWD)/pkg":/pkg libv8-node:gnu cp $@ /pkg/ +lib: src/node-v$(NODE_VERSION)/out/Release/libv8_monolith.a -pkg/libv8-node-$(VERSION)-aarch64-linux-musl.gem: - docker build --platform linux/arm64 --build-arg RUBY_VERSION=2.4-alpine --progress plain -t libv8-node:musl . - docker run --platform linux/arm64 --rm -it -v "$(PWD)/pkg":/pkg libv8-node:musl cp $@ /pkg/ +gem: pkg/libv8-node-$(VERSION)-$(CPU)-$(OS).gem -test/x86_64-linux: pkg/libv8-node-$(VERSION)-x86_64-linux.gem - test -d test/mini_racer || git clone https://github.com/rubyjs/mini_racer.git test/mini_racer --depth 1 - cd test/mini_racer && git fetch origin refs/pull/186/head && git checkout FETCH_HEAD && git reset --hard && git clean -f -d -x - ruby -i -ne '$$_ =~ /^\s+LIBV8_NODE_VERSION/ ? print(" LIBV8_NODE_VERSION = \"$(VERSION)\"\n") : print' test/mini_racer/lib/mini_racer/version.rb - docker run --platform linux/amd64 --rm -it -v "$(PWD)/test:/code/test" -w "/code/test/mini_racer" libv8-node:gnu sh -c 'gem install ../../$< && bundle install && bundle exec rake compile && bundle exec rake test' +test: test/$(CPU)-$(OS) -test/x86_64-linux-musl: pkg/libv8-node-$(VERSION)-x86_64-linux-musl.gem - test -d test/mini_racer || git clone https://github.com/rubyjs/mini_racer.git test/mini_racer --depth 1 - cd test/mini_racer && git fetch origin refs/pull/186/head && git checkout FETCH_HEAD && git reset --hard && git clean -f -d -x - ruby -i -ne '$$_ =~ /^\s+LIBV8_NODE_VERSION/ ? print(" LIBV8_NODE_VERSION = \"$(VERSION)\"\n") : print' test/mini_racer/lib/mini_racer/version.rb - docker run --platform linux/amd64 --rm -it -v "$(PWD)/test:/code/test" -w "/code/test/mini_racer" libv8-node:musl sh -c 'gem install ../../$< && bundle install && bundle exec rake compile && bundle exec rake test' +ctest: vendor/v8 + cd test/gtest && cmake -S . -B build && cd build && cmake --build . && ctest -test/aarch64-linux: pkg/libv8-node-$(VERSION)-aarch64-linux.gem - test -d test/mini_racer || git clone https://github.com/rubyjs/mini_racer.git test/mini_racer --depth 1 - cd test/mini_racer && git fetch origin refs/pull/186/head && git checkout FETCH_HEAD && git reset --hard && git clean -f -d -x - ruby -i -ne '$$_ =~ /^\s+LIBV8_NODE_VERSION/ ? print(" LIBV8_NODE_VERSION = \"$(VERSION)\"\n") : print' test/mini_racer/lib/mini_racer/version.rb - docker run --platform linux/arm64 --rm -it -v "$(PWD)/test:/code/test" -w "/code/test/mini_racer" libv8-node:gnu sh -c 'gem install ../../$< && bundle install && bundle exec rake compile && bundle exec rake test' +src/node-v$(NODE_VERSION).tar.gz: + ./libexec/download-node $(NODE_VERSION) + +src/node-v$(NODE_VERSION): src/node-v$(NODE_VERSION).tar.gz + ./libexec/extract-node $(NODE_VERSION) + +src/node-v$(NODE_VERSION)/out/Release/node: src/node-v$(NODE_VERSION) + ./libexec/build-libv8 $(NODE_VERSION) + +src/node-v$(NODE_VERSION)/out/Release/libv8_monolith.a: src/node-v$(NODE_VERSION)/out/Release/node + ./libexec/build-monolith $(NODE_VERSION) + +vendor/v8: src/node-v$(NODE_VERSION)/out/Release/libv8_monolith.a + ./libexec/inject-libv8 $(NODE_VERSION) + +pkg/libv8-node-$(VERSION)-$(CPU)-$(OS).gem: vendor/v8 + bundle exec rake binary -test/aarch64-linux-musl: pkg/libv8-node-$(VERSION)-aarch64-linux-musl.gem +test/$(CPU)-$(OS): pkg/libv8-node-$(VERSION)-$(CPU)-$(OS).gem test -d test/mini_racer || git clone https://github.com/rubyjs/mini_racer.git test/mini_racer --depth 1 - cd test/mini_racer && git fetch origin refs/pull/186/head && git checkout FETCH_HEAD && git reset --hard && git clean -f -d -x + cd test/mini_racer && git fetch origin v0.6.3 && git checkout -f FETCH_HEAD && git reset --hard && git clean -f -d -x ruby -i -ne '$$_ =~ /^\s+LIBV8_NODE_VERSION/ ? print(" LIBV8_NODE_VERSION = \"$(VERSION)\"\n") : print' test/mini_racer/lib/mini_racer/version.rb - docker run --platform linux/arm64 --rm -it -v "$(PWD)/test:/code/test" -w "/code/test/mini_racer" libv8-node:musl sh -c 'gem install ../../$< && bundle install && bundle exec rake compile && bundle exec rake test' + ruby -i -ne '$$_ =~ /spec.required_ruby_version/ ? "" : print' test/mini_racer/mini_racer.gemspec + cd test/mini_racer && env TOP="$(PWD)" GEM_HOME="$(PWD)/test/bundle/ruby/$(RUBY_VERSION)" BUNDLE_PATH="$(PWD)/test/bundle" sh -c 'rm -rf "$${GEM_HOME}" && gem install $${TOP}/$< && bundle install && bundle exec rake compile && bundle exec rake test' diff --git a/Makefile.docker b/Makefile.docker new file mode 100644 index 0000000..e66a188 --- /dev/null +++ b/Makefile.docker @@ -0,0 +1,65 @@ +PWD := $(shell pwd) +OS := $(shell uname -s | tr '[A-Z]' '[a-z]') +CPU := $(shell uname -m) +VERSION := $(shell ./libexec/metadata version) +NODE_VERSION := $(shell ./libexec/metadata node_version) +RUBY_VERSION = $(shell ruby -e 'puts RUBY_VERSION.gsub(/\d+$$/, "0")') + +vars: + @echo $(PWD) + @echo $(OS) $(CPU) + @echo $(VERSION) $(NODE_VERSION) + @echo $(RUBY_VERSION) + +all: gem test + +gem: pkg/libv8-node-$(VERSION)-$(CPU)-$(OS).gem + +test: test/$(CPU)-$(OS) + +test/linux: test/$(subst arm64,aarch64,$(CPU))-linux +test/linux-musl: test/$(subst arm64,aarch64,$(CPU))-linux-musl + +pkg/libv8-node-$(VERSION)-x86_64-linux.gem: + docker build --platform linux/amd64 --build-arg RUBY_VERSION=2.7 --build-arg NODE_VERSION=$(NODE_VERSION) --progress plain -t libv8-node:$(VERSION)-gnu . + docker run --platform linux/amd64 --rm -it -v "$(PWD)/pkg":/pkg libv8-node:$(VERSION)-gnu cp $@ /pkg/ + +pkg/libv8-node-$(VERSION)-x86_64-linux-musl.gem: + docker build --platform linux/amd64 --build-arg RUBY_VERSION=2.7-alpine --build-arg NODE_VERSION=$(NODE_VERSION) --progress plain -t libv8-node:$(VERSION)-musl . + docker run --platform linux/amd64 --rm -it -v "$(PWD)/pkg":/pkg libv8-node:$(VERSION)-musl cp $@ /pkg/ + +pkg/libv8-node-$(VERSION)-aarch64-linux.gem: + docker build --platform linux/arm64 --build-arg RUBY_VERSION=2.7 --build-arg NODE_VERSION=$(NODE_VERSION) --progress plain -t libv8-node:$(VERSION)-gnu . + docker run --platform linux/arm64 --rm -it -v "$(PWD)/pkg":/pkg libv8-node:$(VERSION)-gnu cp $@ /pkg/ + +pkg/libv8-node-$(VERSION)-aarch64-linux-musl.gem: + docker build --platform linux/arm64 --build-arg RUBY_VERSION=2.7-alpine --build-arg NODE_VERSION=$(NODE_VERSION) --progress plain -t libv8-node:$(VERSION)-musl . + docker run --platform linux/arm64 --rm -it -v "$(PWD)/pkg":/pkg libv8-node:$(VERSION)-musl cp $@ /pkg/ + +test/x86_64-linux: pkg/libv8-node-$(VERSION)-x86_64-linux.gem + test -d test/mini_racer || git clone https://github.com/rubyjs/mini_racer.git test/mini_racer --depth 1 + cd test/mini_racer && git fetch origin v0.6.3 && git checkout -f FETCH_HEAD && git reset --hard && git clean -f -d -x + ruby -i -ne '$$_ =~ /^\s+LIBV8_NODE_VERSION/ ? print(" LIBV8_NODE_VERSION = \"$(VERSION)\"\n") : print' test/mini_racer/lib/mini_racer/version.rb + ruby -i -ne '$$_ =~ /spec.required_ruby_version/ ? "" : print' test/mini_racer/mini_racer.gemspec + docker run --platform linux/amd64 --rm -it -v "$(PWD)/test:/code/test" -w "/code/test/mini_racer" libv8-node:$(VERSION)-gnu sh -c 'gem install ../../$< && bundle install && bundle exec rake compile && bundle exec rake test' + +test/x86_64-linux-musl: pkg/libv8-node-$(VERSION)-x86_64-linux-musl.gem + test -d test/mini_racer || git clone https://github.com/rubyjs/mini_racer.git test/mini_racer --depth 1 + cd test/mini_racer && git fetch origin v0.6.3 && git checkout -f FETCH_HEAD && git reset --hard && git clean -f -d -x + ruby -i -ne '$$_ =~ /^\s+LIBV8_NODE_VERSION/ ? print(" LIBV8_NODE_VERSION = \"$(VERSION)\"\n") : print' test/mini_racer/lib/mini_racer/version.rb + ruby -i -ne '$$_ =~ /spec.required_ruby_version/ ? "" : print' test/mini_racer/mini_racer.gemspec + docker run --platform linux/amd64 --rm -it -v "$(PWD)/test:/code/test" -w "/code/test/mini_racer" libv8-node:$(VERSION)-musl sh -c 'gem install ../../$< && bundle install && bundle exec rake compile && bundle exec rake test' + +test/aarch64-linux: pkg/libv8-node-$(VERSION)-aarch64-linux.gem + test -d test/mini_racer || git clone https://github.com/rubyjs/mini_racer.git test/mini_racer --depth 1 + cd test/mini_racer && git fetch origin v0.6.3 && git checkout -f FETCH_HEAD && git reset --hard && git clean -f -d -x + ruby -i -ne '$$_ =~ /^\s+LIBV8_NODE_VERSION/ ? print(" LIBV8_NODE_VERSION = \"$(VERSION)\"\n") : print' test/mini_racer/lib/mini_racer/version.rb + ruby -i -ne '$$_ =~ /spec.required_ruby_version/ ? "" : print' test/mini_racer/mini_racer.gemspec + docker run --platform linux/arm64 --rm -it -v "$(PWD)/test:/code/test" -w "/code/test/mini_racer" libv8-node:$(VERSION)-gnu sh -c 'gem install ../../$< && bundle install && bundle exec rake compile && bundle exec rake test' + +test/aarch64-linux-musl: pkg/libv8-node-$(VERSION)-aarch64-linux-musl.gem + test -d test/mini_racer || git clone https://github.com/rubyjs/mini_racer.git test/mini_racer --depth 1 + cd test/mini_racer && git fetch origin v0.6.3 && git checkout -f FETCH_HEAD && git reset --hard && git clean -f -d -x + ruby -i -ne '$$_ =~ /^\s+LIBV8_NODE_VERSION/ ? print(" LIBV8_NODE_VERSION = \"$(VERSION)\"\n") : print' test/mini_racer/lib/mini_racer/version.rb + ruby -i -ne '$$_ =~ /spec.required_ruby_version/ ? "" : print' test/mini_racer/mini_racer.gemspec + docker run --platform linux/arm64 --rm -it -v "$(PWD)/test:/code/test" -w "/code/test/mini_racer" libv8-node:$(VERSION)-musl sh -c 'gem install ../../$< && bundle install && bundle exec rake compile && bundle exec rake test' diff --git a/Rakefile b/Rakefile index ade35ea..99467ee 100644 --- a/Rakefile +++ b/Rakefile @@ -23,9 +23,7 @@ task :compile, [:platform] => [] do |_, args| local_platform = Gem::Platform.local target_platform = Gem::Platform.new(ENV['RUBY_TARGET_PLATFORM'] || args.to_h[:platform] || Gem::Platform.local) - if target_platform.os == 'darwin' - target_platform.instance_eval { @version = nil } - end + target_platform.instance_eval { @version = nil } if target_platform.os == 'darwin' puts "local platform: #{local_platform}" puts "target platform: #{target_platform}" @@ -46,9 +44,7 @@ task :binary, [:platform] => [:compile] do |_, args| local_platform = Gem::Platform.local.dup target_platform = Gem::Platform.new(ENV['RUBY_TARGET_PLATFORM'] || args.to_h[:platform] || Gem::Platform.local) - if target_platform.os == 'darwin' - target_platform.instance_eval { @version = nil } - end + target_platform.instance_eval { @version = nil } if target_platform.os == 'darwin' puts "local platform: #{local_platform}" puts "target platform: #{target_platform}" diff --git a/ext/libv8-node/builder.rb b/ext/libv8-node/builder.rb index 84eae98..dab2771 100644 --- a/ext/libv8-node/builder.rb +++ b/ext/libv8-node/builder.rb @@ -1,4 +1,4 @@ -unless $LOAD_PATH.include?(File.expand_path('../../lib', __dir__)) +unless $LOAD_PATH.include?(File.expand_path('../../lib', __dir__)) # rubocop:disable Style/IfUnlessModifier $LOAD_PATH.unshift(File.expand_path('../../lib', __dir__)) end require 'libv8/node/version' diff --git a/ext/libv8-node/extconf.rb b/ext/libv8-node/extconf.rb index 20bc370..31b9692 100644 --- a/ext/libv8-node/extconf.rb +++ b/ext/libv8-node/extconf.rb @@ -1,6 +1,12 @@ # frozen_string_literal: true require 'mkmf' + +if RUBY_ENGINE == 'truffleruby' + File.write('Makefile', dummy_makefile($srcdir).join('')) # rubocop:disable Style/GlobalVars + return +end + create_makefile('libv8-node') require File.expand_path('location', __dir__) diff --git a/ext/libv8-node/location.rb b/ext/libv8-node/location.rb index 9b4cf68..07acff8 100644 --- a/ext/libv8-node/location.rb +++ b/ext/libv8-node/location.rb @@ -45,7 +45,7 @@ def configure(context = MkmfContext.new) def verify_installation! include_paths = Libv8::Node::Paths.include_paths - unless include_paths.detect { |p| Pathname(p).join('v8.h').exist? } + unless include_paths.detect { |p| Pathname(p).join('v8.h').exist? } # rubocop:disable Style/IfUnlessModifier raise(HeaderNotFound, "Unable to locate 'v8.h' in the libv8 header paths: #{include_paths.inspect}") end diff --git a/ext/libv8-node/paths.rb b/ext/libv8-node/paths.rb index 79abbc0..0fe38cc 100644 --- a/ext/libv8-node/paths.rb +++ b/ext/libv8-node/paths.rb @@ -20,7 +20,7 @@ def object_paths end def platform - Gem::Platform.local.to_s.gsub(/-darwin-?\d+/, '-darwin') + Gem::Platform.local.tap { |p| RUBY_PLATFORM =~ /musl/ && p.version.nil? && p.instance_eval { @version = 'musl' } }.to_s.sub(/-darwin\K-?\d+|-linux\K-gnu\z/, '') end def config diff --git a/lib/libv8/node/version.rb b/lib/libv8/node/version.rb index 1160d71..4a5390a 100644 --- a/lib/libv8/node/version.rb +++ b/lib/libv8/node/version.rb @@ -1,7 +1,7 @@ module Libv8; end module Libv8::Node - VERSION = '16.10.0.0'.freeze - NODE_VERSION = '16.10.0'.freeze - LIBV8_VERSION = '9.3.345.19'.freeze # from v8/include/v8-version.h + VERSION = '16.19.0.0'.freeze + NODE_VERSION = '16.19.0'.freeze + LIBV8_VERSION = '9.4.146.26'.freeze # from v8/include/v8-version.h end diff --git a/libexec/build-libv8 b/libexec/build-libv8 index 0511122..c3303b9 100755 --- a/libexec/build-libv8 +++ b/libexec/build-libv8 @@ -29,8 +29,8 @@ eval "$("${libexec}/platform")" echo "configure: ${configure_flags}" echo "compilers: CC='${CC}' CXX='${CXX}' CC_host='${CC_host:-}' CXX_host='${CXX_host:-}'" -"${CC}" -v -"${CXX}" -v +${CC} -v +${CXX} -v # shellcheck disable=SC2086 "${PYTHON}" configure ${configure_flags} @@ -38,5 +38,13 @@ echo "compilers: CC='${CC}' CXX='${CXX}' CC_host='${CC_host:-}' CXX_host='${CXX_ 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 diff --git a/libexec/build-monolith b/libexec/build-monolith index 16c0bac..600697d 100755 --- a/libexec/build-monolith +++ b/libexec/build-monolith @@ -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}" diff --git a/libexec/inject-libv8 b/libexec/inject-libv8 index 353d4ed..2142e1e 100755 --- a/libexec/inject-libv8 +++ b/libexec/inject-libv8 @@ -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" diff --git a/libexec/platform b/libexec/platform index 85ed12d..91343aa 100755 --- a/libexec/platform +++ b/libexec/platform @@ -15,8 +15,16 @@ 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) +triple=$(${CC} -dumpmachine) host_platform="${triple}" target_platform="${TARGET_PLATFORM:-${1:-}}" target_platform="${target_platform:-${host_platform}}" @@ -42,14 +50,17 @@ case "${target_platform}" in ;; x86_64*-darwin*) # not for cross compilation - RUBY_TARGET_PLATFORM="$(ruby -e 'puts Gem::Platform.local.to_s.gsub(/-darwin-?\d+/, "-darwin")')" + RUBY_TARGET_PLATFORM='x86_64-darwin' ;; arm64*-darwin*) # not for cross compilation - RUBY_TARGET_PLATFORM="$(ruby -e 'puts Gem::Platform.local.to_s.gsub(/-darwin-?\d+/, "-darwin")')" + RUBY_TARGET_PLATFORM='arm64-darwin' ;; *) - # not for cross compilation + if [ "${host_platform}" != "${target_platform}" ]; then + echo 'cross compilation not supported' + exit 1 + fi RUBY_TARGET_PLATFORM="$(ruby -e 'puts Gem::Platform.local.to_s')" ;; esac @@ -60,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 @@ -81,6 +97,30 @@ if [ "${host_platform}" != "${target_platform}" ]; then STRIP='arm-linux-gnueabihf-strip' configure_flags='--dest-cpu=arm --cross-compiling --dest-os=linux --with-arm-float-abi=hard --with-arm-fpu=neon' ;; + x86_64-*linux*) + CC='x86_64-linux-gnu-gcc' + CXX='x86_64-linux-gnu-g++' + CC_host='gcc' + CXX_host='g++' + STRIP='x86_64-linux-gnu-strip' + configure_flags='--dest-cpu=x86_64 --cross-compiling --dest-os=linux' + ;; + x86_64*-darwin*) + CC='clang -arch x86_64' + CXX='clang++ -arch x86_64' + CC_host='clang' + CXX_host='clang++' + STRIP='strip' + configure_flags='--dest-cpu=x86_64 --cross-compiling --dest-os=mac' + ;; + arm64*-darwin*) + CC='clang -arch arm64' + CXX='clang++ -arch arm64' + CC_host='clang' + CXX_host='clang++' + STRIP='strip' + configure_flags='--dest-cpu=arm64 --cross-compiling --dest-os=mac' + ;; *) configure_flags='' ;; @@ -102,11 +142,31 @@ fi # ;; # esac +if command -v ccache >/dev/null 2>&1; then + if [ -n "${CC:-}" ] && [ "${CC}" = "${CC#ccache}" ]; then + CC="ccache ${CC}" + CXX="ccache ${CXX}" + fi + + if [ -n "${CC_host:-}" ] && [ "${CC_host}" = "${CC_host#ccache}" ]; then + CC_host="ccache ${CC_host}" + CXX_host="ccache ${CXX_host}" + fi +fi + cat < 12' - s.add_development_dependency 'rubocop', '~> 0.50.0' + s.add_development_dependency 'rubocop', '~> 1.44.0' end diff --git a/sums/v16.17.0.sum b/sums/v16.17.0.sum new file mode 100644 index 0000000..a8c2aa7 --- /dev/null +++ b/sums/v16.17.0.sum @@ -0,0 +1 @@ +2a2e6262739741f98ab81648a50891861dbf66f12413b93f1a97b4c71570611e diff --git a/sums/v16.19.0.sum b/sums/v16.19.0.sum new file mode 100644 index 0000000..ea3f21b --- /dev/null +++ b/sums/v16.19.0.sum @@ -0,0 +1 @@ +8b8a2939fa5f654ff61cae29b12118c24109273458ecbe6162ad8a8858309e0d diff --git a/test/gtest/.gitignore b/test/gtest/.gitignore new file mode 100644 index 0000000..86201ed --- /dev/null +++ b/test/gtest/.gitignore @@ -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 diff --git a/test/gtest/CMakeLists.txt b/test/gtest/CMakeLists.txt new file mode 100644 index 0000000..915947c --- /dev/null +++ b/test/gtest/CMakeLists.txt @@ -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) diff --git a/test/gtest/Framework.h b/test/gtest/Framework.h new file mode 100644 index 0000000..ed54c59 --- /dev/null +++ b/test/gtest/Framework.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include +#include + +struct Framework { + typedef std::function basic_main; + typedef std::function iso_main; + typedef std::function&)> ctx_main; + + inline static void run(basic_main main) { + std::shared_ptr 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 ctx = v8::Context::New(iso); + v8::Context::Scope cScope { ctx }; + + main(ctx); + }); + } +}; \ No newline at end of file diff --git a/test/gtest/c_v8_tests.cc b/test/gtest/c_v8_tests.cc new file mode 100644 index 0000000..28d4345 --- /dev/null +++ b/test/gtest/c_v8_tests.cc @@ -0,0 +1,18 @@ +#include + +#include +#include + +#include "Framework.h" + +// Demonstrate some basic assertions. +TEST(FRLocaleTest, LocaleTests) { + Framework::runWithContext([](v8::Local& ctx) -> void { + v8::Local script = v8::Script::Compile(ctx, v8::String::NewFromUtf8Literal(ctx->GetIsolate(), "new Date('April 28 2021').toLocaleDateString('fr-FR');")).ToLocalChecked(); + v8::Local result = script->Run(ctx).ToLocalChecked(); + v8::Local resultStr = result->ToString(ctx).ToLocalChecked(); + v8::String::Utf8Value resultUTF8(ctx->GetIsolate(), resultStr); + + EXPECT_STREQ(*resultUTF8, "28/04/2021"); + }); +} diff --git a/test/gtest/check_glibc.c b/test/gtest/check_glibc.c new file mode 100644 index 0000000..38e7e4b --- /dev/null +++ b/test/gtest/check_glibc.c @@ -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 + +#ifndef __GLIBC__ +#error "__GLIBC__ is undef -- not glibc!" +#endif + +int main() { } +