Skip to content
This repository has been archived by the owner on Jan 28, 2024. It is now read-only.

Globals #139

Merged
merged 10 commits into from
Jan 13, 2021
24 changes: 19 additions & 5 deletions lib/src/code_generator/global.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// 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.

import 'package:ffigen/src/code_generator/typedef.dart';

import 'binding.dart';
import 'binding_string.dart';
import 'type.dart';
Expand Down Expand Up @@ -34,6 +36,21 @@ class Global extends LookUpBinding {
dartDoc: dartDoc,
);

List<Typedef>? _typedefDependencies;
@override
List<Typedef> getTypedefDependencies(Writer w) {
if (_typedefDependencies == null) {
_typedefDependencies = <Typedef>[];

// Add typedef's required by the variable's type.
final valueType = type.getBaseType();
if (valueType.broadType == BroadType.NativeFunction) {
_typedefDependencies!.addAll(valueType.nativeFunc!.getDependencies());
}
}
return _typedefDependencies!;
}

@override
BindingString toBindingString(Writer w) {
final s = StringBuffer();
Expand All @@ -42,12 +59,9 @@ class Global extends LookUpBinding {
s.write(makeDartDoc(dartDoc!));
}

final holderVarName =
w.wrapperLevelUniqueNamer.makeUnique('_$globalVarName');
s.write(
'${w.ffiLibraryPrefix}.Pointer<${type.getCType(w)}> $holderVarName;\n');
final refOrValue = type.broadType == BroadType.Struct ? 'ref' : 'value';
s.write(
"${type.getDartType(w)} get $globalVarName => ($holderVarName ??= ${w.dylibIdentifier}.lookup<${type.getCType(w)}>('$originalName')).value;\n\n");
"late final ${type.getDartType(w)} $globalVarName = ${w.dylibIdentifier}.lookup<${type.getCType(w)}>('$originalName').$refOrValue;\n\n");
Copy link
Contributor

Choose a reason for hiding this comment

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

I think global variables are not constants, they can be changed.

If that's the case, we should instead add getters and setters for this.

So for an int global variable, we can do this -

  late final ffi.Pointer<ffi.Int32> _globalVar =
      _dylib.lookup<ffi.Int32>('globalVar');

  int get globalVar => _globalVar.value;

  set globalVar(int value) => _globalVar.value = value;

Copy link
Author

Choose a reason for hiding this comment

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

Yes, this works for all types except structs, which just don't have a setter, but fields for structs can be set from the ref that is obtained via the getter.


return BindingString(type: BindingStringType.global, string: s.toString());
}
Expand Down
13 changes: 13 additions & 0 deletions lib/src/config_provider/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ class Config {
Declaration get unnamedEnumConstants => _unnamedEnumConstants;
late Declaration _unnamedEnumConstants;

/// Declaration config for Globals.
Declaration get globals => _globals;
late Declaration _globals;

/// Declaration config for Macro constants.
Declaration get macroDecl => _macroDecl;
late Declaration _macroDecl;
Expand Down Expand Up @@ -222,6 +226,15 @@ class Config {
extractedResult: (dynamic result) =>
_unnamedEnumConstants = result as Declaration,
),
strings.globals: Specification<Declaration>(
requirement: Requirement.no,
validator: declarationConfigValidator,
extractor: declarationConfigExtractor,
defaultValue: () => Declaration(),
extractedResult: (dynamic result) {
_globals = result as Declaration;
},
),
strings.macros: Specification<Declaration>(
requirement: Requirement.no,
validator: declarationConfigValidator,
Expand Down
31 changes: 31 additions & 0 deletions lib/src/header_parser/sub_parsers/var_parser.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
TimWhiting marked this conversation as resolved.
Show resolved Hide resolved
// 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.

import 'package:ffigen/src/code_generator.dart';
import 'package:ffigen/src/header_parser/data.dart';
import 'package:logging/logging.dart';

import '../clang_bindings/clang_bindings.dart' as clang_types;
import '../data.dart';
import '../utils.dart';

final _logger = Logger('ffigen.header_parser.var_parser');

/// Parses a global variable
Global? parseVarDefinition(clang_types.CXCursor cursor) {
final type = cursor.type().toCodeGenType();
if (type.broadType == BroadType.Unimplemented) {
TimWhiting marked this conversation as resolved.
Show resolved Hide resolved
_logger
.warning('Global Type not supported $type ${cursor.type().spelling()}');
Copy link
Contributor

Choose a reason for hiding this comment

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

Add these logs instead.

_logger.fine(
          '---- Removed Global, reason: unsupported type: ${cursor.completeStringRepr()}');
_logger.warning(
      "Skipped global variable '$globalName', type not supported.");

Copy link
Author

Choose a reason for hiding this comment

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

Done

return null;
}
final g = Global(
originalName: cursor.spelling(),
TimWhiting marked this conversation as resolved.
Show resolved Hide resolved
name: config.globals.renameUsingConfig(cursor.spelling()),
usr: cursor.usr(),
type: cursor.type().toCodeGenType(),
dartDoc: getCursorDocComment(cursor),
);
return g;
}
4 changes: 4 additions & 0 deletions lib/src/header_parser/translation_unit_parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'dart:ffi';

import 'package:ffigen/src/code_generator.dart';
import 'package:ffigen/src/header_parser/sub_parsers/macro_parser.dart';
import 'package:ffigen/src/header_parser/sub_parsers/var_parser.dart';
import 'package:logging/logging.dart';

import 'clang_bindings/clang_bindings.dart' as clang_types;
Expand Down Expand Up @@ -58,6 +59,9 @@ int _rootCursorVisitor(clang_types.CXCursor cursor, clang_types.CXCursor parent,
case clang_types.CXCursorKind.CXCursor_MacroDefinition:
saveMacroDefinition(cursor);
break;
case clang_types.CXCursorKind.CXCursor_VarDecl:
addToBindings(parseVarDefinition(cursor));
TimWhiting marked this conversation as resolved.
Show resolved Hide resolved
break;
default:
_logger.finer('rootCursorVisitor: CursorKind not implemented');
}
Expand Down
1 change: 1 addition & 0 deletions lib/src/strings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const functions = 'functions';
const structs = 'structs';
const enums = 'enums';
const unnamedEnums = 'unnamed-enums';
const globals = 'globals';
const macros = 'macros';

// Sub-fields of Declarations.
Expand Down
9 changes: 3 additions & 6 deletions test/code_generator_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -436,14 +436,11 @@ final ffi.DynamicLibrary _dylib;
/// The symbols are looked up in [dynamicLibrary].
Bindings(ffi.DynamicLibrary dynamicLibrary): _dylib = dynamicLibrary;

ffi.Pointer<ffi.Int32> _test1;
int get test1 => (_test1 ??= _dylib.lookup<ffi.Int32>('test1')).value;
late final int test1 = _dylib.lookup<ffi.Int32>('test1').value;

ffi.Pointer<ffi.Pointer<ffi.Float>> _test2;
ffi.Pointer<ffi.Float> get test2 => (_test2 ??= _dylib.lookup<ffi.Pointer<ffi.Float>>('test2')).value;
late final ffi.Pointer<ffi.Float> test2 = _dylib.lookup<ffi.Pointer<ffi.Float>>('test2').value;

ffi.Pointer<ffi.Pointer<Some>> _test5;
ffi.Pointer<Some> get test5 => (_test5 ??= _dylib.lookup<ffi.Pointer<Some>>('test5')).value;
late final ffi.Pointer<Some> test5 = _dylib.lookup<ffi.Pointer<Some>>('test5').value;

}

Expand Down