Skip to content
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] Refactor into BuildInput #1871

Merged
merged 20 commits into from
Jan 8, 2025
Merged

Conversation

dcharkes
Copy link
Collaborator

@dcharkes dcharkes commented Jan 7, 2025

This PR changes the public API according to #1738, and should have minimal behavior changes.

Everything in HookConfig causes a different input.outputDirectory, all the other elements in the input do not.

  • This leads to the packageName no longer influencing the checksum, so the default output directory has been changed to .dart_tool/native_assets_builder/$packageName/$checksum.

Follow up PRs:

  • Serialize to a new JSON format
  • get rid of cCompiler envScript

Design:

Copy link

github-actions bot commented Jan 7, 2025

PR Health

Breaking changes ✔️
Package Change Current Version New Version Needed Version Looking good?
Changelog Entry ✔️
Package Changed Files

Changes to files need to be accounted for in their respective changelogs.

API leaks ✔️

The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.

Package Leaked API symbols
License Headers ✔️
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
Files
no missing headers

All source files should start with a license header.

Unrelated files missing license headers
Files
pkgs/jni/lib/src/third_party/generated_bindings.dart
pkgs/native_assets_builder/test_data/native_dynamic_linking/bin/native_dynamic_linking.dart
pkgs/objective_c/lib/src/ns_input_stream.dart

@coveralls
Copy link

coveralls commented Jan 7, 2025

Coverage Status

coverage: 87.893% (-0.008%) from 87.901%
when pulling a8bc599 on input-refactor
into 3b66738 on main.

@dcharkes dcharkes requested a review from mkustermann January 7, 2025 22:50
@mkustermann
Copy link
Member

In general I think this is good, I haven't looked at the code yet, but from commit message

    input.targetConfig.linkingEnabled; // build only
    input.targetConfig.dryRun; // build only, deleted soon
    // c.2. per asset
    input.targetConfig.buildAssetTypes;
    input.targetConfig.codeConfig.linkModePreference;
    input.targetConfig.codeConfig.targetArchitecture;
    input.targetConfig.codeConfig.targetOS;
    input.targetConfig.codeConfig.androidConfig.targetNdkApi;
    input.targetConfig.codeConfig.iOSConfig.targetSdk;
    input.targetConfig.codeConfig.iOSConfig.targetVersion;
    input.targetConfig.codeConfig.macOSConfig.targetVersion;

input.targetConfig.buildAssetTypes does sound a bit strange. The "target" terminology we somewhat already use for targetOS / targetArchitecture / targetPlatform / .... I'd probably prefer input.buildConfig but since we know it's a BuildInput already why not just input.config that has a type of BuildConfig / LinkConfig?

input.targetConfig.codeConfig.targetArchitecture also sounds strange as we have "config" twice in the name and "target" twice in the name. Now that we do not have the ambituity in linker input of input.code (code assets) vs input.codeConfig anymore, we could drop the "config" and just go with input.config.code.{ios,android,...} (of type {Build,Link}Input.{Build,Link}Config.CodeConfig.{IOSConfig,AndroidConfig,...}).

Lastly, given these changes and choice of checksuming, I think we should probably rename input.outputDirectory to something that indicates it's per-config, possibly input.configSpecificOutputDirectory (or better name) and input.sharedOutputDirectory - it's then clear to any reader that the former is per-config and the ladder is not.

so the default output directory has been changed to .dart_tool/native_assets_builder/$packageName/$checksum.

That may be a good thing, so users can easily see what takes up most space and can selectively rm -rf .dart_tool/native_assets_builder/<problematic-package>/

@dcharkes
Copy link
Collaborator Author

dcharkes commented Jan 8, 2025

Done.

The API now looks like this:

void main(List<String> args) async {
  await build(args, (input, output) async {
    // a. shared
    input.packageName;
    input.packageRoot;
    input.outputDirectory;
    input.outputDirectoryShared;
    // b. hook-specific
    input.metadata; // build only
    input.assets.code; // link only
    input.assets.data; // link only
    input.recordedUsagesFile; // link only
    // c. target config
    // c.1. per hook
    input.config.linkingEnabled; // build only
    input.config.dryRun; // build only, deleted soon
    // c.2. per asset
    input.config.buildAssetTypes;
    input.config.code.linkModePreference;
    input.config.code.targetArchitecture;
    input.config.code.targetOS;
    input.config.code.android.targetNdkApi;
    input.config.code.iOS.targetSdk;
    input.config.code.iOS.targetVersion;
    input.config.code.macOS.targetVersion;
    input.config.code.cCompiler?.archiver;
    input.config.code.cCompiler?.compiler;
    input.config.code.cCompiler?.linker;

    output.assets.code.add(CodeAsset(
      package: 'package',
      name: 'name',
      linkMode: DynamicLoadingBundled(),
      os: input.config.code.targetOS,
      architecture: input.config.code.targetArchitecture,
      file: input.outputDirectory.resolve('foo'),
    ));
    output.assets.data.add(
      DataAsset(
        file: input.outputDirectory.resolve('foo'),
        name: 'name',
        package: 'package',
      ),
      linkInPackage: 'foo',
    );
    output.addDependency(input.packageRoot.resolve('x.txt'));
  });
}

I also dropped the Config suffixes in the setup method names and parameters.

    final inputBuilder = LinkInputBuilder()
      ..setupShared(
        packageName: packageName,
        packageRoot: packageRootUri,
        outputDirectory: outDirUri,
        outputDirectoryShared: outputDirectoryShared,
      )
      ..setupLink(
        assets: assets,
        recordedUsesFile: null,
      )
      ..config.setupShared(buildAssetTypes: [CodeAsset.type])
      ..config.setupCode(
        targetOS: OS.android,
        targetArchitecture: Architecture.arm64,
        android: AndroidConfig(targetNdkApi: 30),
        linkModePreference: LinkModePreference.preferStatic,
        cCompiler: CCompilerConfig(
          compiler: fakeClang,
          linker: fakeLd,
          archiver: fakeAr,
          envScript: fakeVcVars,
          envScriptArgs: ['arg0', 'arg1'],
        ),
      );

Lastly, given these changes and choice of checksumming, I think we should probably rename input.outputDirectory to something that indicates it's per-config, possibly input.configSpecificOutputDirectory (or better name) and input.sharedOutputDirectory - it's then clear to any reader that the former is per-config and the ladder is not.

I can't really come up with good names. I'd like to avoid making the names longer and also avoid making the names unrelated. Maybe adding documentation is enough. I believe that most users should be using outputDirectory so that should have the most plain name.

Copy link
Member

@mkustermann mkustermann left a comment

Choose a reason for hiding this comment

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

A few comments, the main one is about layering and buildAssetTypes.

required BuildValidator buildValidator,
required ApplicationAssetValidator applicationAssetValidator,
required Uri workingDirectory,
PackageLayout? packageLayout,
String? runPackageName,
required List<String> buildAssetTypes,
Copy link
Member

Choose a reason for hiding this comment

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

Why did you remove this?

The current code has separation based on how the protocol is layered:

  • The optional things / protocol extensions are handled by embedder by calling out to it (e.g. code config)
  • The core protocol is handled in package:native_assets_builder, this field is core protocol support

So the build and link methods should take all things it needs for the core protocol, thereby ensuring those are setup as required by core protocol.

By moving it to the embedder, the package:native_assets_builder can no longer guarantee the core protocol fields are setup, it relies on the embedder to handle core protocol functionality - which doesn't seem right to me.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oops, I forgot to revert this when I added buildAssetTypes back in. Thanks!

..setupCodeConfig(
inputCreator: () => BuildInputBuilder()
..config.setupShared(buildAssetTypes: [
CodeAsset.type,
Copy link
Member

Choose a reason for hiding this comment

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

Before it was DataAsset only, why did you have to add CodeAsset here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We shouldn't be calling setupCode below without the CodeAsset.type here.
We need the setupCode to ensure differences in the directories.

I guess it's technically correct to add more config that's never read by anyone, but it's messy.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe the setupCode call should be removed instead if it worked with data assets only?

There's 3 things that should be in sync

  • the buildAssetTypes
  • the config
  • the validation

With your changes we support code assets but it doesn't validate them, see

    buildValidator: (input, output) async =>
        await validateDataAssetBuildOutput(input, output),

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If we work with data assets only, then we don't exercise the fact that we can have both identical and non-identical output directories. This test is doing directory locking and concurrency.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Adding the code validator

pkgs/native_assets_cli/lib/src/api/link.dart Outdated Show resolved Hide resolved
pkgs/native_assets_cli/lib/src/data_assets/config.dart Outdated Show resolved Hide resolved
pkgs/native_assets_cli/lib/src/validation.dart Outdated Show resolved Hide resolved
pkgs/native_assets_cli/tool/rename.dart Outdated Show resolved Hide resolved
pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart Outdated Show resolved Hide resolved
@dcharkes dcharkes requested a review from mkustermann January 8, 2025 12:08
@dcharkes dcharkes marked this pull request as ready for review January 8, 2025 12:08
Copy link
Member

@mkustermann mkustermann left a comment

Choose a reason for hiding this comment

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

lgtm with comment

@dcharkes
Copy link
Collaborator Author

dcharkes commented Jan 8, 2025

lgtm with comment

Thanks for the quick roundtrip @mkustermann! 🙏

I don't see a comment, did you forget to press send?

@dcharkes
Copy link
Collaborator Author

dcharkes commented Jan 8, 2025

I don't see a comment, did you forget to press send?

Oh, it's in an existing conversation. Yay to GitHub UI. 🙈

@auto-submit auto-submit bot merged commit e4c4bd6 into main Jan 8, 2025
41 checks passed
@auto-submit auto-submit bot deleted the input-refactor branch January 8, 2025 12:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants