rubyjs / libv8-node

Package libv8 from Node
MIT License
14 stars 27 forks source link

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

Closed seanmakesgames closed 1 year ago

seanmakesgames commented 1 year ago

Fixes rubyjs/mini_racer#259 Unblocks rubyjs/mini_racer#271 and rubyjs/mini_racer#261 Also adds first c++ test.

Fixes #40

seanmakesgames commented 1 year ago

@lloeki - @Fayti1703 was able to reproduce the issue on his machine and did a bit of digging:

I have it down to something missing in icu-small (ures_open) is setting U_MISSING_RESOURCE_ERROR = 2 (/*< The requested resource cannot be found /). Not sure what exactly, nor where node is getting that data from. I have a guess -- there's an extern variable that is being macro'd together in node.cc, starting with icusmdt... but good luck figuring out where that is actually defined. I'm kinda wondering if node changed how they package the data for ICU into the binary, which means libv8-node is not pulling it with the lib anymore ...ok so turns out there's a icudt71_dat variable, which looks like it's the ICU data... no idea how exactly the node binary gets to it, its not being referred to in the source code from what I can see, but it does appear in the symbol tables for both libnode* and libv8_monolith.a, so probably just a matter of hooking it in there Might want to expose a method in libv8-node to do that so any other API consumers don't have to worry about it too much and instead just call an init method before using V8

I just noticed that full-icu is referenced in the build-libv8 script. https://github.com/rubyjs/libv8-node/blob/master/libexec/build-libv8#L26

I assume you have a bit of context here @lloeki ?

seanmakesgames commented 1 year ago

I have also confirmed that the issue does not reproduce in the built node executable src/node-v16.19.0/out/Release/node

Fayti1703 commented 1 year ago

Managed to figure out what's going on with the crashing... turns out the monolith build script was including stubdata.o off of small-icu -- a file that includes an ICU data directory with zero entries (not even for the root locale!)

The compiler apparently found that object first when building dependent programs, so we were getting literally zero ICU data, which V8 isn't set up to handle.

Dropping the stubdata.o object from the libv8_monolith.a means the compiler instead finds the real data from icudt71_dat.o, which that fixes the crash issue (at least, in a simple test program).

I will note that the extra ! -path conditional to find might need some cross-OS testing, though. If it doesn't work on a specific OS, you can replace that with ar d $LIBV8_MONOLITH stubdata.o after collecting the objects.

Fayti1703 commented 1 year ago

Something I just noticed: d742196 and 5cb6e87 conflict with 0edfea99d30e9e9b0915a8d22b6b6fa3da8df99b on master (from #31).

For the former, that's not a huge problem, it's basically a subset of the conflicting commit (though not quite because I pass -S and run ranlib; they don't) so we could just drop it, but the latter commit will need conflict resolution. Nothing too complicated, I think, but worth noting.

lloeki commented 1 year ago

Thanks for the investigation!

That find sure looks ugly now 😅 I've got some old attempt at implementing these shell scripts in Ruby; someday I'll complete that which should make these much more readable and consistent.

As for the conflicts, let's fix node-16 first and we'll sort that out afterwards.

seanmakesgames commented 1 year ago

I'm taking @Fayti1703 's test code and putting it into the test framework now. It should pass as a first case added. Additional new cases can be added easily afterwards. Then we can get back to 'the task at hand' of upgrading node/v8. :)

lloeki commented 1 year ago

As for the real real fix for the root cause, I presume it would entail having a true libv8_monolith.a target landed in upstream node / libv8 build system, otherwise this class of issue (either missing or extra inclusion of object files) may show up again.

Fayti1703 commented 1 year ago

That find sure looks ugly now :sweat_smile: I've got some old attempt at implementing these shell scripts in Ruby; someday I'll complete that which should make these much more readable and consistent.

I think it's not that bad. Adding a few line continuations and indents in the find arguments would help already... plus, we could move the main part outside the case and only set variables for the system find/ar/ranlib binaries rather than writing the same thing 3 times.

Can add those changes to this PR if you're interested, @lloeki.

Fayti1703 commented 1 year ago

As for the real real fix for the root cause, I presume it would entail having a true libv8_monolith.a target landed in upstream node / libv8 build system

Yeah, that would be the ideal solution... though we might be able to parse out the object files that are being linked into the libnode.so from make -n libnode output and determine what objects we need from there.

Plus, it looks like v8 is already bundled into a couple .a files, so we could potentially just merge those...

lloeki commented 1 year ago

Nah, don't sweat it, it was in jest regarding the stuff I need to get back to someday. Let's keep it simple, this is good enough to get us out of this hole.

Plus, it looks like v8 is already bundled into a couple .a files, so we could potentially just merge those...

IIRC I tried that a long time ago but it was not sufficient.

seanmakesgames commented 1 year ago

Got some first attempts at stuff in there. Am working on linux/darwin conditional linking now. Then onto actions integration. This is my first time with cmake (and it's been more than a few years since I wrangled compilers) ;) Let me know if you see anything you want changed.

seanmakesgames commented 1 year ago

Hey @lloeki -

I found this in the readme

See BUILDING.md. Also make sure to read CONTRIBUTING.md if you plan to help.

These files don't seem to exist-- did they move or something? I feel like we should throw a few things in here for our future selves.

seanmakesgames commented 1 year ago

@lloeki Looks like the workflows file does not use the makefile at the top level at all- is that intentional? I'm trying to figure out where to put the ctest build and run commands, and it looks like maybe the libexec script files, but they are kind of mixed?

seanmakesgames commented 1 year ago

Not sure why my actions are not showing up in the checks tab, but they are showing up over here for those who are curious: https://github.com/seanmakesgames/libv8-node/actions

Fayti1703 commented 1 year ago

Not sure why my actions are not showing up in the checks tab

That tab is for actions on a PR in the base repository (i.e. rubyjs/libv8-node in this case). If this PR were ready to merge, and there were any actions defined on PRs, they'd run and show up there.

seanmakesgames commented 1 year ago

there were any actions defined on PRs, they'd run and show up there.

Strange though- I thought push was a wider net than pr -- since pushing to -any- branch will run the actions. In any case, the actions should pass before we merge. :D

Fayti1703 commented 1 year ago

Quick update here: The state at 0f1dc90

In any case, I would like to do a cleanup pass over the commits prior to merging them in, though I think it's best to defer that to after we have an acceptable resulting tree. I'll let @lloeki be the judge of when we're at that point.

lloeki commented 1 year ago

See BUILDING.md. Also make sure to read CONTRIBUTING.md if you plan to help. These files don't seem to exist-- did they move or something? I feel like we should throw a few things in here for our future selves.

Hmm, not sure. Maybe I forgot to add these. Feel free to fill some stuff in if you're keen on it!

A separate PR from this one would be good.

lloeki commented 1 year ago

Looks like the workflows file does not use the makefile at the top level at all- is that intentional?

Yeah, kind of.

So there are three "high level" build "orchestrators" currently:

I plan to unify and simplify these, hence my unpublished attempt to have libexec stuff be written in Ruby

lloeki commented 1 year ago

I'm trying to figure out where to put the ctest build and run commands, and it looks like maybe the libexec script files, but they are kind of mixed?

Hmm, good question. I don't think this should be published in the gem, so I would refrain from having it in libexec. I think a couple of shell files inside of test would be OK for now, to be called by some Makefile targets and GH workflow steps (but not ext/libv8-node/builder.rb)

(excluding the latter because e.g I don't want people to need cmake when installing from source)

seanmakesgames commented 1 year ago

Hey @lloeki We are very close to ready here. Can you give what we've done a good look over to let us know anything you'd like us to change here?

Additionally, do you know what is breaking the mini_racer test portions of the ci?

Fayti1703 commented 1 year ago

Update to the previous build status:

seanmakesgames commented 1 year ago

@lloeki or @SamSaffron We need your help here. We've fixed most of the stuff, but there are a handful of varied failures in the tests of mini_racer's use of libv8:

https://github.com/seanmakesgames/libv8-node/actions/runs/3951363807

Maybe some of these can be ignored, because they are fixed in later branches / versions of libv8 and ruby? but I don't remember.

SamSaffron commented 1 year ago

Amazing! ... Ruby 2.6 is EOL. I think we can remove it from the test matrix. That would just leave Ruby 2.7 and up issues (and 2.7 is EOL pretty soon)

So mostly the issues left are around localization missing on base test VM ?

seanmakesgames commented 1 year ago

Amazing! ... Ruby 2.6 is EOL. I think we can remove it from the test matrix. That would just leave Ruby 2.7 and up issues (and 2.7 is EOL pretty soon)

🥳 🎉

So mostly the issues left are around localization missing on base test VM ?

When looking just at the 3.0 and 3.1 failing tests, yep!

@Fayti1703 I wonder if the ruby compile scripts are just missing some flags that you added to the other build jobs to get the languages linking up correctly. or- maybe that needs to be added into mini_racer code?

Fayti1703 commented 1 year ago

So mostly the issues left are around localization missing on base test VM ?

@Fayti1703 I wonder if the ruby compile scripts are just missing some flags that you added to the other build jobs to get the languages linking up correctly. or- maybe that needs to be added into mini_racer code?

I believe that's a problem with the OS / container setup -- the ICU data is dynamically built using data from... somewhere whenever node itself is built.

Fayti1703 commented 1 year ago

Something I just noticed about the ruby platform tests: They don't seem to use the ruby platform gem at all. It's compiled and installed alright, but the actual "Test with mini_racer" step then turns around and downloads libv8-node with the "correct" arch + libc from https://rubygems.org/

Fayti1703 commented 1 year ago

(force-pushed without any changes to the resulting tree to clean up the history a bit)

seanmakesgames commented 1 year ago

This last commit! NICE @Fayti1703!

We are VERY green. @lloeki @SamSaffron Please take a look.

SamSaffron commented 1 year ago

Amazing ... give it is all green lets merge this.

What are the next steps we need here to publish a new version? Super keen to publish a new mini_racer

lloeki commented 1 year ago

What are the next steps we need here to publish a new version?

@SamSaffron since mini_racer version constraint on libv8-node is ~> 16.10.0.0 and this is clearly a bug fix, there is nothing to be done for node-16 on the mini_racer side, only pushing the new node 16 gems.

The typical libv8-node release process (that I should document) is:

(Most of these can be automated via GH workflows, e.g tag => create GH release + attack artifacts + push to rubygems†. or it can be a manual GH "dispatch workflow")

† this one can also both require and wait for 2FA with some interesting techniques

The degraded libv8-node release process is the same, except (when CI is broken because reasons outside of release blockers):

lloeki commented 1 year ago

That said, the plan to update node major now should be:

Then:

Fayti1703 commented 1 year ago

I'd be willing to rebase the changes here onto the node-17 branch and open a PR for them. Just need a go-ahead and a couple of minutes (most likely).

seanmakesgames commented 1 year ago

@Fayti1703 has created the rebase, and we are working on test stabilization now:

41

lloeki commented 1 year ago

FYI I'm working on getting a 16.19.0.0 gem release out.

lloeki commented 1 year ago

@SamSaffron since mini_racer version constraint on libv8-node is ~> 16.10.0.0 and this is clearly a bug fix

Duh I was confused, it's going to be 16.19.0.1 not 16.10.0.1. It's a bug fix from the tentative 16.19.0.0 I pushed but is not used yet by mini_racer.

Once pushed I'll open a PR for that version bump in mini_racer.

lloeki commented 1 year ago

Got CI fully green on the node-16 branch: https://github.com/rubyjs/libv8-node/actions/runs/4002211129

For a proper release CI is still missing aarch64-linux-musl though. Two options:

I'll assess which one would be the quickest and do that. Then I can do the release.

Fayti1703 commented 1 year ago

Another option would be to build a cross-compiled aarch64 musl-libc and using the gcc-wrapper from that on a Debian container... though I don't know how complicated that would be to set up in CI.

lloeki commented 1 year ago

That's a valid option although it's trumped by going the clang route (whether with a Debian base + musl sysroot or with Alpine) which is much easier to handle.

lloeki commented 1 year ago

Going clang may also enable libc/libc++ independent builds, see here for some of this "portable" stuff: https://github.com/DataDog/libddwaf/tree/9caeac92a11ee7d43bf5d0d1453723409ac30f3f/docker/libddwaf#portable-libddwaf-on-any-linux-26