Skip to content

feat: merge ASARs #34

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 4 commits into from
Jan 24, 2022

Conversation

indutny-signal
Copy link
Contributor

@indutny-signal indutny-signal commented Dec 16, 2021

In short, this adds a new option fuseASARs that, instead of checking that ASARs are exactly the same, will attempt to fuse them together into one and run lipo on shared bindings.

uniqueAllowList` option handles files that are unique to each ASAR. Ultimately the goal is to put all of them together in the final ASAR, but I decided to go with an explicit allowlist so that the end user will always be aware of the extra files.

This helped us reduce universal .dmg size from 300mb to 240mb because we have quite a lot of data in our asar file at Signal.

Example of debug output

  electron-universal fusing x64 and arm64 asars +16ms
  electron-universal Fusing /var/folders/9f/5h519zwn7kz7rbwr_wr7sptm0000gn/T/electron-universal-VDiwOl/Tmp.app/Contents/Resources/app.asar and /Users/indutny/Code/signalapp/Signal-Desktop-Private/release/mac-universal--arm64/Signal.app/Contents/Resources/app.asar +1ms
  electron-universal Extracting /var/folders/9f/5h519zwn7kz7rbwr_wr7sptm0000gn/T/electron-universal-VDiwOl/Tmp.app/Contents/Resources/app.asar to /var/folders/9f/5h519zwn7kz7rbwr_wr7sptm0000gn/T/x64-Vfv57T +985ms
  electron-universal Extracting /Users/indutny/Code/signalapp/Signal-Desktop-Private/release/mac-universal--arm64/Signal.app/Contents/Resources/app.asar to /var/folders/9f/5h519zwn7kz7rbwr_wr7sptm0000gn/T/arm64-imyBcQ +2s
  electron-universal Creating unique directory: node_modules/@signalapp/signal-client/prebuilds/darwin-arm64 +2s
  electron-universal Copying unique file: node_modules/@signalapp/signal-client/prebuilds/darwin-arm64/node.napi.node +1ms
  electron-universal Copying unique file: node_modules/ringrtc/build/darwin/libringrtc-arm64.node +6ms
  electron-universal Creating unique directory: node_modules/sharp/vendor/8.11.3/darwin-arm64v8 +12ms
  electron-universal Copying unique file: node_modules/sharp/vendor/8.11.3/darwin-arm64v8/platform.json +0ms
  electron-universal Copying unique file: node_modules/sharp/vendor/8.11.3/darwin-arm64v8/versions.json +2ms
  electron-universal Creating unique directory: node_modules/sharp/vendor/8.11.3/darwin-arm64v8/lib +0ms
  electron-universal Copying unique file: node_modules/sharp/vendor/8.11.3/darwin-arm64v8/lib/libvips-cpp.42.dylib +0ms
  electron-universal Copying unique file: node_modules/sharp/build/Release/sharp-darwin-arm64v8.node +22ms
  electron-universal Fusing binding: node_modules/better-sqlite3/build/Release/better_sqlite3.node +3ms
  electron-universal Creating archive at /var/folders/9f/5h519zwn7kz7rbwr_wr7sptm0000gn/T/electron-universal-VDiwOl/Tmp.app/Contents/Resources/app.asar +28ms
  electron-universal Done fusing +11s
  electron-universal copying snapshot file Contents/Frameworks/Electron Framework.framework/Versions/A/Resources/v8_context_snapshot.arm64.bin to target application +2s
  electron-universal moving final universal app to target destination +4ms

0xcffaedfe,

// Universal
0xcafebabe,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe there's a slight risk of misidentifying Java bytecode files as macho, but in that case lipo will fail anyway so maybe we shouldn't bother?

Comment on lines 80 to 82
x64,
arm64,
output,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these all be more specific, I assume they're paths to asar files?

So x64AsarPath, arm64AsarPath, outputAsarPath, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack.

x64,
arm64,
output,
lipo = 'lipo',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the path / name of the lipo binary? If so let's go with lipoPath, more indicative

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also why is this an option, it isn't a user-facing option and afaics we don't do anything similar elsewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Let's drop this.

src/index.ts Outdated
Comment on lines 34 to 41
/**
* Fuse x64 and arm64 ASARs into one.
*/
fuseASARs?: boolean;
/**
* Minimatch pattern of paths that are allowed to be unique in ASARs.
*/
fuseASARsAllowList?: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if they're on this list, does it take the x64 file? the arm64 file? etc.

I think it would be better to somehow allow folks to choose, or preferably not allow this at all. It leads to uncertainty, you should just form your ASAR file correctly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if they're on this list, does it take the x64 file? the arm64 file? etc.

It takes either x64 or arm64 file that is not present in the other platform's asar.

I think it would be better to somehow allow folks to choose, or preferably not allow this at all. It leads to uncertainty, you should just form your ASAR file correctly.

The "unique" files in this jargon will likely have platform specific name (e.g. node_modules/sharp/build/${platform}-${arch}, at least this is what we see at Signal Desktop), and so I believe that this option is usable in the current form. The motivation for introducing it is that I wanted users to have complete control over which files are going to be introduced into ASAR. My worry is that there might be a package that won't play well with such merging scheme and users won't know about it until it will start crashing in production.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, so these files to be clear exist in one asar but do not exist in the other? 🤔 I don't know what a better name is but it's definitely not clear what that does if I didn't grok it first try.

Maybe singleArchFiles or something idk, open to ideas here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see, so these files to be clear exist in one asar but do not exist in the other? 🤔 I don't know what a better name is but it's definitely not clear what that does if I didn't grok it first try.

You got it right.

Maybe singleArchFiles or something idk, open to ideas here.

singleArchFiles certainly sounds better than what I came up with, let me change it to this. I'm out of ideas, otherwise!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed.

src/index.ts Outdated
/**
* Fuse x64 and arm64 ASARs into one.
*/
fuseASARs?: boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we not use the word "fuse" here as fuses are a different Electron concept.

Either mergeASARs or lipoNativeModules might be better options here. The latter definition if we remove the allow list option below because then that's all this option does.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to mergeASARs, which is frankly what I came up originally 😂

const destination = await fs.realpath(path.resolve(x64Dir, binding));

d(`fusing binding: ${binding}`);
execFileSync(lipo, [source, destination, '-create', '-output', destination]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of the way MACHO_MAGIC works couldn't this be trying to fuse universal/x64 or x64 and x64 that don't match? Not familiar enough with lipo to know what happens when you try to merge things like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I should just drop the Universal constant from MACHO_MAGIC. The merging of x64 and x64 would fail AFAIK and it should be fine because the binding binaries shouldn't be different unless they were compiled for different platforms!

@indutny-signal
Copy link
Contributor Author

Thanks for looking into this @MarshallOfSound . I've addressed your feedback with the latest push.

@indutny-signal
Copy link
Contributor Author

Realized that I forgot to drop Universal signatures from MACHO_MAGIC. Should be ready for another look if you have time. Thanks!

@indutny-signal indutny-signal changed the title feat: fuse ASARs feat: merge ASARs Jan 20, 2022
@indutny-signal
Copy link
Contributor Author

Friendly ping @MarshallOfSound

@MarshallOfSound MarshallOfSound merged commit 38ab1c3 into electron:master Jan 24, 2022
@electron-bot
Copy link

🎉 This PR is included in version 1.2.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@indutny-signal indutny-signal deleted the feature/fuse-asars branch January 24, 2022 21:55
@indutny-signal
Copy link
Contributor Author

Yay, thank you so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants