Skip to content

Conversation

@jacksonrl
Copy link

@jacksonrl jacksonrl commented Dec 9, 2025

fixes #2816.

This allows headers like this to work:

typedef WGPUFlags WGPUBufferUsage;
static const WGPUBufferUsage WGPUBufferUsage_None = 0x0000000000000000;

source: https://github.com/webgpu-native/webgpu-headers/blob/12c1d34e7464cac58cc41a24aeee1d48a2f21b74/webgpu.h#L1266

Currently the generated code looks like this:

  late final ffi.Pointer<WGPUBufferUsage> _WGPUBufferUsage_None =
      _lookup<WGPUBufferUsage>('WGPUBufferUsage_None');

  int get WGPUBufferUsage_None => _WGPUBufferUsage_None.value;

  set WGPUBufferUsage_None(int value) => _WGPUBufferUsage_None.value = value;

But this doesn't work for me and also seems incorrect (creating a setter for a static const?). It seems that static const variables are not included in the lookup table, at least when I tried to access it, it failed for me. See the linked issue for more explanation.

I moved _getWrittenRepresentation and _writeDoubleAsString to utils to make them public. I also changed

Global? parseVarDeclaration to Binding? parseVarDeclaration.

I'm opening this PR in the hopes of getting some feedback on if this is the right way to solve the issue. It seems to me to be correct but I'm also not familiar with the codebase.

Also, this is a breaking change. RIght now this test is failing:

/** Version of the native C library */
const char* const library_version = "1.0.0-native";

which used to genrate

/// Version of the native C library
@ffi.Native<ffi.Pointer<ffi.Char>>()
external final ffi.Pointer<ffi.Char> library_version;

but now is

const String library_version = '1.0.0-native';

edit: I should have looked into this more before opening the PR, but it also seems that maybe this issue only happens with integral types, so maybe this isn't needed for Strings, in which case I should remove that. Marking as draft for now, but if anyone has any thought or suggestions please let me know.


  • I’ve reviewed the contributor guide and applied the relevant portions to this PR.
Contribution guidelines:

Many Dart repos have a weekly cadence for reviewing PRs - please allow for some latency before initial review feedback.

Note: The Dart team is trialing Gemini Code Assist. Don't take its comments as final Dart team feedback. Use the suggestions if they're helpful; otherwise, wait for a human reviewer.

@jacksonrl jacksonrl changed the title ffigen: Generate Dart constants for static const C variables [ffigen] Generate Dart constants for static const C variables Dec 9, 2025
@jacksonrl jacksonrl marked this pull request as draft December 9, 2025 04:08
@liamappelbe liamappelbe self-requested a review December 9, 2025 04:45
@github-actions
Copy link

github-actions bot commented Dec 9, 2025

PR Health

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/hooks_runner/test_data/download_assets/hook/build.dart
pkgs/jni/test/debug_release_test.dart
pkgs/objective_c/example/command_line/lib/main.dart
pkgs/objective_c/lib/src/ns_input_stream.dart

This check can be disabled by tagging the PR with skip-license-check.

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 symbol Leaking sources

This check can be disabled by tagging the PR with skip-leaking-check.

Breaking changes ✔️
Package Change Current Version New Version Needed Version Looking good?

This check can be disabled by tagging the PR with skip-breaking-check.

Changelog Entry ✔️
Package Changed Files

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

This check can be disabled by tagging the PR with skip-changelog-check.

@coveralls
Copy link

coveralls commented Dec 9, 2025

Coverage Status

coverage: 92.126% (+0.05%) from 92.081%
when pulling 8c4f8a3 on jacksonrl:static-const
into 21b2bf7 on dart-lang:main.

@liamappelbe
Copy link
Contributor

Thanks for your contribution! The overall approach looks good to me.

In your bug, you mentioned that we're generating setters for these variables. It seems like this PR doesn't address that issue (which is fine, that can be fixed in a separate PR). I see we're already plumbing through cType.isConstQualified to Global, so I wonder why you were seeing setters being generated. It looks like if the clang const eval fails, it falls back to the existing code path, and generates a global variable, so it's possible that issue will still exist after this PR. This change may make it harder to repro that bug though, so maybe it's worth fixing that first?

I haven't looked into why supposedly const Globals are generating setters. At a glance, it looks like Global.toBindingString is correctly looking at the constant field to decide whether to generate the setter. So maybe the issue is that clang is not reporting the constness correctly? But if that's the case then this PR won't fix the issue, since it's also relying on cType.isConstQualified. I recommend debugging this by adding prints to parseVarDeclaration to see if cType.isConstQualified is correct for the cases in the original bug.

Also, this is a breaking change.

That's fine. The next release of FFIgen (v21) is a breaking change anyway, and this is clearly an improvement.

it also seems that maybe this issue only happens with integral types, so maybe this isn't needed for Strings, in which case I should remove that.

Proxying whenever possible seems like a good thing to me. If a string can be proxied, it probably should be, since this improves readability and is also a small performance win.

@jacksonrl
Copy link
Author

jacksonrl commented Dec 9, 2025

@liamappelbe Thank for reviewing!

outdated

I actually just created a simple test linked in #2816 (comment) which I think shows that this would be needed for static const strings as well so I'll re-open this draft.

In your bug, you mentioned that we're generating setters for these variables. It seems like this PR doesn't address that issue

Well, it does fix it in that now there are no getter or setters, just a dart value. (edit: or maybe not, let me check if it actually worked...)

I see we're already plumbing through cType.isConstQualified to Global, so I wonder why you were seeing setters being generated.

I'm not sure either. I was getting this when creating bindings to Dawn. Everything else worked and I can call into Dawn fine, just can't use these static consts.

so it's possible that issue will still exist after this PR. This change may make it harder to repro that bug though, so maybe it's worth fixing that first?

Yes, that make sense, although I don't know how to repro or diagnose the bug.

But if that's the case then this PR won't fix the issue, since it's also relying on cType.isConstQualified. I recommend debugging this by adding prints to parseVarDeclaration to see if cType.isConstQualified is correct for the cases in the original bug.

Ok. I will try re-running the bindings on dawn with my fork to see if the bug goes away. And I will try these debug prints.

edit: I re-ran ffigen and indeed now it creates usable bindings:


const int WGPUBufferUsage_None = 0;

const int WGPUBufferUsage_MapRead = 1;


So I'm not sure about how that works. I just remembered though that I reproed this issue without Dawn, using just this header:

#define MY_MACRO_CONST 100

int my_global_var;

const int my_const_var;

static int my_static_var = 200;

static const int my_static_const_var = 300;

So now I'll try to repro that again.

Ok, turns out the setter for static const vars was only happening with a very old version. (I had been using version 10.) So that's probably why. I should have looked at the version before opening that bug or forking the repo :) I think this PR is still needed to be able to use static const values though..

@jacksonrl jacksonrl marked this pull request as ready for review December 9, 2025 05:06
@jacksonrl
Copy link
Author

Turns out that broken test should not have been broken, it was opted in to get the memory address for that string like so:

globals:
  symbol-address:
    include:
      - library_version

latest commit should fix that.

Copy link
Contributor

@liamappelbe liamappelbe left a comment

Choose a reason for hiding this comment

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

Looks good. Just a few minor formatting issues.

- __Breaking change__: Certain synthetic USRs have been modified to ensure they
cannot collide with real USRs. It's very unlikely that any user facing USRs
are affected.
- __Breaking change__: Dart const values will be generated for global variables marked const in C (e.g. static const int) instead of symbol lookups. This supports integers, doubles, and string literals. Including the variable name in the globals -> symbol-address configuration will still generate symbol lookups.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Use an 80 column wrap.

entry-points:
- static_const.h
include-directives:
- '**static_const.h' No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Add a trailing newline


// Should be generated as Globals.
static const char TEST_STRING_ARRAY[] = "test_array";
int test_global; No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Add a trailing newline

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.

[ffigen] const globals should be proxied in dart(?)

3 participants