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

Build fails in precompile due to missing classes it's supposed to generate #3632

Open
frank06 opened this issue Dec 27, 2023 · 8 comments
Open

Comments

@frank06
Copy link

frank06 commented Dec 27, 2023

Getting a failure during precompile:

$ dart run build_runner build -d -v

Building package executable... (7.2s)
Built build_runner:build_runner.
[INFO] Entrypoint:Generating build script...
[INFO] Entrypoint:Generating build script completed, took 389ms

[INFO] Bootstrap:Precompiling build script......
[WARNING] Bootstrap:
lib/main.dart:3:8: Error: Error when reading 'lib/objectbox.g.dart': No such file or directory
import 'package:ob_test/objectbox.g.dart';
       ^
lib/main.dart:13:14: Error: 'Store' isn't a type.
  late final Store store;
             ^^^^^
lib/main.dart:15:13: Error: Method not found: 'openStore'.
    store = openStore();
            ^^^^^^^^^
// ...


[SEVERE] Bootstrap:
Failed to precompile build script .dart_tool/build/entrypoint/build.dart.
This is likely caused by a misconfigured builder definition.

This methods are generated by Objectbox. But the build fails way before giving the chance to Objectbox to generate them. It's a catch 22.

build_runner: ^2.4.6, Dart SDK version: 3.1.2 (stable)

Using Objectbox, which has two builders: resolver, generator.

I created my own to run before resolver, as it generates code that should be consumed by resolver.

builders:
  data_model_builder:
    import: "package:ob_test/builders/data_model_builder.dart"
    builder_factories: ["dataModelBuilder"]
    build_extensions: { "$lib$": ["entities.g.dart"] }
    auto_apply: dependents
    build_to: source
    runs_before: ["objectbox_generator|resolver"]

I've seen data_model_builder properly output entities.g.dart so I know it's some configuration issue.

What is the right config for running my builder before Objectbox?

@frank06
Copy link
Author

frank06 commented Dec 28, 2023

Added a generate_for to try and limit the Dart files read, but doesn't help.

If I remove my builder I get no No such file or directory errors. Why?

@frank06
Copy link
Author

frank06 commented Dec 28, 2023

Attempting a different approach. Instead of creating a pre-generator, I forked the resolver and deal with the differences in Dart code.

I went from

  resolver:
    import: "package:objectbox_generator/objectbox_generator.dart"
    builder_factories: ["entityResolverFactory"]
    # build_extensions: Required. A map from input extension to the list of output extensions that may be created
    # for that input. This must match the merged buildExtensions maps from each Builder in builder_factories.
    build_extensions: { ".dart": [".objectbox.info"] }
    auto_apply: dependents
    build_to: cache

to

  resolver:
    import: "package:ob_test/builders/entity_resolver.dart"
    builder_factories: ["entityResolverFactory"]
    # build_extensions: Required. A map from input extension to the list of output extensions that may be created
    # for that input. This must match the merged buildExtensions maps from each Builder in builder_factories.
    build_extensions: { ".dart": [".objectbox.info"] }
    auto_apply: dependents
    build_to: cache

Only the import changed.

I get the same error as before:

[WARNING] Bootstrap:
lib/main.dart:3:8: Error: Error when reading 'lib/objectbox.g.dart': No such file or directory
import 'package:ob_test/objectbox.g.dart';
       ^
lib/main.dart:13:14: Error: 'Store' isn't a type.
  late final Store store;
             ^^^^^
lib/main.dart:15:13: Error: Method not found: 'openStore'.
    store = openStore();
            ^^^^^^^^^

I'm trying to understand why the original would work but my local copy not. Any help really appreciated, I've been stuck with this for a few days now.

EDIT: just tried with generate_for, in order to exclude lib/objectbox.g.dart

      :resolver:
        enabled: true
        generate_for:
          - lib/models/*.dart

But no, it is still failing

@jakemac53
Copy link
Contributor

jakemac53 commented Jan 5, 2024

Yes, a builder cannot itself depend on generated files from the same build in which it is itself applied (sorry I can't come up with a less confusing way to say that 🤣 ).

We generate a single build script from all the builders that are applied, and that must be fully valid prior to any other compilation. And prior to a build, it may decide to clean up previous generated outputs, which can make a subsequent build fail even if a previous one succeeded (maybe the files were generated before the new builder was added).

There are some unsupported ways to manage this (restore the generated files for source control after the first failure), but the best thing to do is move the libraries that require code generation into another, different package. That way it has a separate build from the place where it is being used.

@jakemac53 jakemac53 added the needs-info Additional information needed from the issue author label Jan 5, 2024
@github-actions github-actions bot removed the needs-info Additional information needed from the issue author label Jan 6, 2024
@jakemac53 jakemac53 added the needs-info Additional information needed from the issue author label Jan 19, 2024
@frank06
Copy link
Author

frank06 commented Jan 29, 2024

I think I understood, thanks.

I encountered the same issue when working on Flutter Data. Since the library contains builders, this means that I cannot use Objectbox to generate Flutter Data source code.

Can build chains be defined in Dart instead of YAML? Sorry, I appreciate your work and definitely don't intend to offend anyone, but I'm finding it very confusing and time consuming : always trying to tweak YAML files by copy-pasting snippets from github issues and crossing my fingers for it to work. Docs don't seem to cover the common use-cases I come across.

More generally, do you know of any other effort in Dart-land to improve the build situation? Is this the only way of generating code?

@jakemac53
Copy link
Contributor

Can build chains be defined in Dart instead of YAML?

They can, yes. If you look at the generated build script that you get from a normal build, at .dart_tool/build/entrypoint/build.dart you will see what that looks like. Essentially, you can use the build_runner_core package, instead of the build_runner package, to create your own build script.

The APIs are intended to be code-generation friendly (from build.yaml files) more than user friendly, but it is possible to create your own still.

@jakemac53
Copy link
Contributor

Note also, that a builder you depend on may change how it is intended to be used, in a way that wouldn't be breaking for normal users, but would break a user creating a custom build script (you might be expected to apply additional builders etc, in a way that would normally be automatic).

@frank06
Copy link
Author

frank06 commented Jan 29, 2024

They can, yes. If you look at the generated build script that you get from a normal build, at .dart_tool/build/entrypoint/build.dart you will see what that looks like. Essentially, you can use the build_runner_core package, instead of the build_runner package, to create your own build script.

Oh this is good news, I'll have a look. Thank you!

@frank06
Copy link
Author

frank06 commented Jan 29, 2024

For those running into the same problem, here is my hack:

#!/bin/bash

mv build.yaml /tmp
dart run build_runner build -d
mv lib/objectbox* /tmp
mv /tmp/build.yaml .
dart run build_runner build -d
mv /tmp/objectbox* lib/
dart run build_runner build -d

Ridiculous, but it works

@github-actions github-actions bot removed the needs-info Additional information needed from the issue author label Jan 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants