-
Notifications
You must be signed in to change notification settings - Fork 53
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
[native_assets_cli] Semantics of one vs multiple hook invocations #1739
Comments
We could consider this. It indeed solves the issue of inconsistent data assets. However, it doesn't solve the issue with inconsistent code assets. Code assets must be provided identically for the various architectures as well.
This is what my very first prototypes had. (Back then os and architecture was combined into "target", so you could build
We probably don't want that, due to Flutter supporting multi-arch apps where we don't want to increase the app size by duplicating assets.
That seems reasonable. 👍 (And is consistent with the checking for code assets. (I hope we have that checking for code assets!)) |
As discussed offline:
Conceptually speaking it would be nice if we could let the framework/embedder decide to invoke per asset type. Then we could completely omit architecture (and even OS) from the invocation to build data assets. |
Thinking in the direction of keeping one invocation with multiple asset types, and keeping one arch for code assets: We have asset-specific config leading to different output directories. Due to the extensible nature of Also, it will be unclear where to put intermediary asset types emitted for linking. E.g. one could emit an If we have the output directories per asset type, you'd still have multiple invocations building the same data asset in flutter multi-arch builds, but hopefully these should be no-ops on subsequent invocations. Thinking in the direction of invoking per asset type, map reduce style: We could merge whatever is emitted metadata-wise. This does require something mergable. E.g. currently it's key value pairs, so we could provide all keys and override values if keys are provided multiple times (or error out). However, we want to go in the direction of using files for metadata (#1251). We should most likely go for a list of metadata files (or keyed metadata files, with a string key).
This becomes somewhat awkward. Especially if you have an external build process outputting a dylib and some binary blob that is included as data. You'd have to invoke that external process both in the data assets invocation and the code assets invocation. (Basically, for a 2 arch build, you'd invoke (hopefully cached) the external process 3 times.) It would be a feature that this forces you to have byte-for-byte the same data assets for different archs in the external process. However, Flutter and Dart don't have multi-OS apps, so it's perfectly fine currently to output a different data asset per OS. And in the data-assets invocation you wouldn't know what the target OS is. (So you can't have your binary blob being different for Android vs host OS.) Thinking in the direction of one invocation per embedder build/run:
This becomes conceptually weird for toolchains now that we have defined the environment variables for the toolchains to be set by the embedder (#1606). I don't believe one can build multi-architecture (x64+arm64) Windows apps, and none of the other OSes currently provide environment variables. But what if some embedder wants to put some archspecific libs in the include path in the environment? If we want to go this direction, we should have a Passing in multiple architectures seems to align pretty well with XCode. It invokes tools with Passing in multiple architectures doesn't align with the clang world. It has different executables for different target archs. Passing in multiple architectures doesn't align with the MSVC world. It requires different env vars for different archs. Passing in multiple architectures doesn't align well with Rust: It requires a single target tripple. Passing in multiple architectures aligns well with the Android world: You can build a jar with dylibs for different target archs in it. So it really seems to depend mostly on whether the packaging for the target OS supports multi-arch-apps. Because in Flutter we do the packaging of multi-arch apps (both for Android and iOS/MacOS), we have been able to hide the complexity so far for building code assets and provide an API that looks a lot like single arch clang/msvc/rust. The question is, when we start adding new asset types, can we abstract that away for users. E.g. if we add a This points into either a single invocation for everything (and refactoring |
With the current status quo, hook invocations to get data assets will not be provided a config that has the OS in it. So one cannot emit per-OS data assets as the hook wouldn't know the OS. (Sidenote: The OS would be the wrong abstraction anyway, because on the web we don't know the OS. So if at all it would be the But what the hook can always do is it can emit N different data assets, e.g. "foo_.data". The Dart code can then use The downside is of course, that the development builds don't do linking and therefore would have more assets bundled than needed. But maybe that's ok? That approach, moving the branching code to Dart doesn't work
|
TL:DR; multi-invocation (single asset type per invocation, single architecture per code-asset invocation). From a discussion with @mkustermann @mosuem @HosseinYousefi and @liamappelbe: Pros for single invocation; build multiple asset types, and multiple architectures for code assets:
Pros for multiple invocation; build one asset type per invocation, and one target architecture for code assets per invocation:
Data assets connected to code assets are painful in either solution (assuming you want to support Flutter hot-reload/hot-restart). I see more pro's for multiple invocations. So let's consider going that direction: Multiple invocations and linking: We can choose to do both multiple and single invocation for link hooks even if build hooks are doing multiple invocations. Pros for multi invocation for linker:
Single invocation for linker:
I can't come up with a use case for the linkers emitting different asset types at the moment. E.g. linkers for native code will pass in static libs. And linkers for any asset type built on top of data assets will pass in these asset types. My current assumption is that linkers really only do tree shaking with the So I'm leaning towards multiple invocations for link hooks as well. Multiple invocations and metadata:
If we go towards multiple invocations, then we could consider changing |
A bundling tool may support multiple asset types. It then has the option to
The motivation for this is for example flutter: Currently flutter has a loop over architectures and performs a build for each of them separately. Now if we add data asset support we are in a strange spot if we say
supportedAssetTypes: [code, data]
for all builds:hook/build.dart
will emit data assets for each of the builds (which differ only in architecture)=> There's room for error, the duplicate data assets could be conflicting (imagine the arm32 build emits data asset with ID
foo
and fileX
, but arm64 build emits data asset with IDfoo
with fileY
)Though flutter only wants one set of data assets irrespective of whether the app runs in arm32 or arm64. So the natural choice is for it to build code assets separately from data assets (and it may not want to supply the architecture for data asset build)
Though that will have implications for our system:
=> already with current system the arm32 and arm64 bit code assets are linked separately, so a linker cannot depend on getting both of them at the same time
To me this sounds somewhat reasonable. It puts more restrictions on the system but allows more flexibility on the bundling tool (e.g. it can ensure data assets don't depend on architecture). It's not entirely ideal because it means sometimes the hook may be invoked with only data asset type with no architecture and sometimes it may be invoked with code+data asset type with architecture, so the second one the hook theoretically could make it's output dependent on the architecture.
The alternatives would be
List<Architecture>
instead of just oneArchitecture
- which then would have other implications (e.g. one may need a per-architecturecCompilerConfig
compiler toolchain, ...)(maybe I'll do that for now)
/cc @dcharkes
The text was updated successfully, but these errors were encountered: