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

Initial generator: functions, structs, enums #2

Merged
merged 91 commits into from
Jun 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
5b984c0
migrated code from dart_ffi_bindings_generator repository
mannprerak2 May 13, 2020
dbcdf6a
update readme: building steps
mannprerak2 May 13, 2020
381be30
code_generation: added function generation for primitives
mannprerak2 May 14, 2020
6eb111d
code_generator: added test for function
mannprerak2 May 14, 2020
2a6b40a
code_generation: added struct generation for primitives, added tests
mannprerak2 May 14, 2020
b0bb97a
code_generation: added pointer support for function and structure, ad…
mannprerak2 May 14, 2020
0b94e5d
tool: added script for basic clang_binding generator
mannprerak2 May 14, 2020
858b99d
code_generator: added constant, global, C string support (ptr to utf8…
mannprerak2 May 15, 2020
4a9cd70
code_generator: added typedefc, added test
mannprerak2 May 15, 2020
f871034
tool: completed basic clang binding generation
mannprerak2 May 15, 2020
b439d57
update readme
mannprerak2 May 15, 2020
c949ec4
simplify setup
dcharkes May 15, 2020
7ddfc4b
Merge pull request #1 from dcharkes/v0.1
mannprerak2 May 15, 2020
d625766
added basic parser logic, fixed visitChildren_wrap function
mannprerak2 May 16, 2020
5e70f2c
copied clang_constants from libclang
mannprerak2 May 16, 2020
0b88589
header_parser: revamped api and code_structure
mannprerak2 May 17, 2020
2ac1821
wrapper.c: added pointer conversion utility, updated bindings
mannprerak2 May 17, 2020
67b5a63
header_parser: basic parser completed
mannprerak2 May 17, 2020
d263047
header_parser: updated exception handling
mannprerak2 May 18, 2020
7fd1468
cleanup
mannprerak2 May 18, 2020
d432d84
Handled Disposing of pointers
mannprerak2 May 18, 2020
b2c5cff
Added input_checker, passing compilerOpts to clang
mannprerak2 May 19, 2020
582a842
fix nullpointer error on compilerOpts list
mannprerak2 May 20, 2020
f00db6d
config_provider: added filtering for functions
mannprerak2 May 21, 2020
b816001
updated lib-clang example to work with clang not in include path, res…
mannprerak2 May 21, 2020
cfc1bae
Multiple Changes
mannprerak2 May 22, 2020
4ddafa1
created a temporary logging solution
mannprerak2 May 23, 2020
af23af0
added typedef struct parser
mannprerak2 May 23, 2020
e8c4a50
cleanup
mannprerak2 May 23, 2020
748a52a
restructured parsing
mannprerak2 May 23, 2020
a763ff0
restructured code
mannprerak2 May 24, 2020
31b0e58
header_parser: added struct parser, minor changes
mannprerak2 May 24, 2020
92b8de5
parser: fixed type extraction
mannprerak2 May 25, 2020
3afc21f
updated libclang-example, minor fix for record_type spelling
mannprerak2 May 25, 2020
b198642
code_generator: added EnumClass, added test
mannprerak2 May 25, 2020
0373f12
header_parser: added enum parsing
mannprerak2 May 25, 2020
da7630e
header_parser: added typedef enums
mannprerak2 May 25, 2020
2d8949d
header_parser: extracted doxygen comment
mannprerak2 May 25, 2020
bc9e509
Added args parsing and logging
mannprerak2 May 28, 2020
7b40bd2
config_provider: added output file option
mannprerak2 May 29, 2020
23c5be3
tests: added native_function_test
mannprerak2 May 29, 2020
dc5875a
code_generator: breaking change
mannprerak2 May 30, 2020
1a857e4
Added support for function pointers in bindings
mannprerak2 May 30, 2020
c8aab08
header_parser: changes, complete libclang_example
mannprerak2 May 30, 2020
a263cec
minor changes
mannprerak2 Jun 1, 2020
9eb0d66
header_parser: added support for multiple headers, header-filters
mannprerak2 Jun 2, 2020
10498f2
header_parser: add structs used by functions
mannprerak2 Jun 2, 2020
80d12cc
config_provider: added sizemap for char, ints
mannprerak2 Jun 3, 2020
48b1289
tests: added simple tests for functions
mannprerak2 Jun 4, 2020
206494c
config_provider: added sort option to config
mannprerak2 Jun 5, 2020
2c5add2
example: added new cJSON example, bug fix
mannprerak2 Jun 5, 2020
4ae311a
linter bug fix, updated code for warnings
mannprerak2 Jun 6, 2020
2e2f2ed
minor changes
mannprerak2 Jun 6, 2020
eaa19aa
logging: improved log comments
mannprerak2 Jun 6, 2020
47b03e7
code_generator: removed global constants file
mannprerak2 Jun 7, 2020
feaaa4c
improved tests, minor changes
mannprerak2 Jun 7, 2020
bb789c6
header_parser: struct fields parsed
mannprerak2 Jun 7, 2020
6e33dc1
parser: extract type from supported typdef
mannprerak2 Jun 8, 2020
59f02ae
header_parser: added workaround for array in struct
mannprerak2 Jun 9, 2020
963c3f3
fix: exclude array of struct in struct
mannprerak2 Jun 9, 2020
90cd5b5
config_provider: revamped internal API
mannprerak2 Jun 9, 2020
94fd06b
Removed generated binding's dependency on package:ffi
mannprerak2 Jun 10, 2020
948a87a
temp: adding cmake
mannprerak2 Jun 10, 2020
e0019d9
WIP: cmakefile
mannprerak2 Jun 10, 2020
74421e4
fix: loading dylib for other platforms
mannprerak2 Jun 11, 2020
75beaec
Added build script for windows: tool/wrapped_libclang/build_dylib_win…
mannprerak2 Jun 13, 2020
eb70797
Windows Testing
mannprerak2 Jun 13, 2020
f7997e1
added warn about removing functions, minor changes
mannprerak2 Jun 15, 2020
1f69ce1
config_provider: minor changes - sizemap, enum, comments
mannprerak2 Jun 15, 2020
3a8f4ee
fixed tests, minor changes
mannprerak2 Jun 16, 2020
9aac26b
Added warning for TU diagnostic errors
mannprerak2 Jun 16, 2020
14f801f
header_parser: handling unimplemented types
mannprerak2 Jun 16, 2020
b7b56c0
update readme, comments
mannprerak2 Jun 18, 2020
a3f7eda
update readme(s), linked todos to github issues
mannprerak2 Jun 18, 2020
bab1513
added copyright notice to code files, update readme(s)
mannprerak2 Jun 19, 2020
c495d73
Self hosting the tool: added libclang_config.yaml
mannprerak2 Jun 19, 2020
8104e5b
Fixed merge conflicts
mannprerak2 Jun 19, 2020
fc4cdbc
Replace platform based build scripts with build.dart
mannprerak2 Jun 19, 2020
c4eaf09
Improved comments in accordance with styleguide
mannprerak2 Jun 20, 2020
e40ddb4
config_provider: refactoring
mannprerak2 Jun 20, 2020
ac137bd
Added 3 lint rules
mannprerak2 Jun 20, 2020
33e7d3a
config_provider: made libclang_dylib_folder optional
mannprerak2 Jun 21, 2020
0cbde77
header_parser: removed file extension checks
mannprerak2 Jun 21, 2020
e12d6f0
minor changes
mannprerak2 Jun 21, 2020
57aefa5
Updated warnings/error logs
mannprerak2 Jun 22, 2020
9646fe8
Minor changes
mannprerak2 Jun 23, 2020
faa561d
minor comment fix
mannprerak2 Jun 23, 2020
0995f25
Updated preamble message
mannprerak2 Jun 24, 2020
10972c8
Updated build.dart, build_test_dylib.dart, Minor changes
mannprerak2 Jun 24, 2020
dc02a76
Minor changes
mannprerak2 Jun 24, 2020
c182022
minor refactoring
mannprerak2 Jun 25, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
# See https://dart.dev/guides/libraries/private-files

# Files and directories created by pub
# Files and directories created by pub.
.dart_tool/
.packages
pubspec.lock

# Directory created by dartdoc.
# If you don't generate documentation locally you can remove this line.
doc/api/

# Avoid committing generated Javascript files:
*.dart.js
*.info.json # Produced by the --dump-info flag.
*.js # When generated by dart2js. Don't specify *.js if your
# project includes source files written in JavaScript.
*.js_
*.js.deps
*.js.map

mannprerak2 marked this conversation as resolved.
Show resolved Hide resolved
# Generated shared libraries.
*.so
*.so.*
*.dylib
*.dll

# Directory for quick experiments.
experiments/

# Files generated by tests for debugging purposes.
test/debug_generated/*
!test/debug_generated/readme.md
2 changes: 2 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
# Name/Organization <email address>

Google LLC

Prerak Mann <[email protected]>
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# 0.1.0
- Initial release supporing binding generation for Functions, Structs, Enums.
- Glob support for specifying headers.
- HeaderFilter - Include/Exclude declarations from specific header files.
- Filters - Include/Exclude function, structs and enum declarations using Regexp or Name matching.
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,69 @@

Experimental generator for [FFI](https://dart.dev/guides/libraries/c-interop)
bindings.

## Example
mannprerak2 marked this conversation as resolved.
Show resolved Hide resolved

For some header file _example.h_:
```C
int sum(int a, int b);
```
Add configurations to Pubspec File:
```yaml
ffigen:
output: 'generated_bindings.dart'
headers:
- 'example.h'
```
Output (_generated_bindings.dart_).
```dart
DynamicLibrary _dylib;

/// Initialises dynamic library
void init(DynamicLibrary dylib) {
_dylib = dylib;
}

int sum(int a,int b) {
return _sum(a,b);
}

final _dart_sum _sum = _dylib.lookupFunction<_c_sum, _dart_sum>('sum');

typedef _c_sum = Int32 Function(Int32 a,Int32 b);

typedef _dart_sum = int Function(int a,int b);
```
## Using this package
- clone/download this repository.
mannprerak2 marked this conversation as resolved.
Show resolved Hide resolved
- Build it (see [building](#building)).
- Add this package as dev_dependency in your `pubspec.yaml`.
- Configurations must be provided in the pubspec.yaml file under the key `ffigen` (or directly under a seperate yaml file which when u specify it passing `--config filename` when running the tool)
- Run the tool- `pub run ffigen:generate`.

## Building
A dynamic library for a wrapper to libclang needs to be generated as it is used by the parser submodule.

#### ubuntu/linux
1. Install libclangdev - `sudo apt-get install libclang-dev`.
2. `cd tool/wrapped_libclang`, then run `dart build.dart`.

mannprerak2 marked this conversation as resolved.
Show resolved Hide resolved
#### Windows
1. Install Visual Studio with C++ development support.
2. Install LLVM.
3. `cd tool\wrapped_libclang`, then run `dart build.dart`.

#### MacOS
1. Install LLVM.
2. `cd tool/wrapped_libclang`, then run `dart build.dart`.

## Trying out examples
1. `cd examples/<example_u_want_to_run>`, Run `pub get`.
2. Run `pub run ffigen:generate`.

## Running Tests
Dynamic library for some tests need to be built before running the examples.
1. `cd test/native_functions_test`.
2. Run `dart build_test_dylib.dart`.

Run tests from the root of the package with `pub run test`.
18 changes: 18 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
# Copyright (c) 2020, 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.

include: package:pedantic/analysis_options.yaml

analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
errors:
omit_local_variable_types: ignore

linter:
rules:
- directives_ordering
mannprerak2 marked this conversation as resolved.
Show resolved Hide resolved
- prefer_final_fields
- prefer_final_locals
- prefer_final_in_for_each
176 changes: 176 additions & 0 deletions bin/generate.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// Copyright (c) 2020, 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.

// Executable script to generate bindings for some C library.
import 'dart:io';

import 'package:args/args.dart';
import 'package:ffigen/src/config_provider.dart';
import 'package:ffigen/src/header_parser.dart' as parser;
import 'package:logging/logging.dart';
import 'package:yaml/yaml.dart' as yaml;

var _logger = Logger('generate.dart');

void main(List<String> args) {
// Parses the cmd args.
final result = getArgResults(args);

// Setup logging level and printing.
setupLogger(result);

// Create a config object.
final config = getConfig(result);

// Parse the bindings according to config object provided.
final library = parser.parse(config);

if (config.sort) {
library.sort();
}

// Generate file for the parsed bindings.
final gen = File(config.output);
library.generateFile(gen);
_logger.info('Finished, Bindings generated in ${gen?.absolute?.path}');
}

Config getConfig(ArgResults result) {
_logger.info('Running in ${Directory.current}');

if (result.wasParsed('config')) {
return getConfigFromCustomYaml(result['config'] as String);
} else {
return getConfigFromPubspec();
}
}

/// Extracts configuration from pubspec file.
Config getConfigFromPubspec() {
final pubspecName = 'pubspec.yaml';
final configKey = 'ffigen';

final pubspecFile = File(pubspecName);

if (!pubspecFile.existsSync()) {
_logger.severe(
'Error: $pubspecName not found, please run this tool from the root of your package.');
exit(1);
}

// Casting this because pubspec is expected to be a YamlMap.

// Throws a [YamlException] if it's unable to parse the Yaml.
final bindingsConfigMap =
yaml.loadYaml(pubspecFile.readAsStringSync())[configKey] as yaml.YamlMap;

if (bindingsConfigMap == null) {
_logger.severe("Couldn't find an entry for '$configKey' in $pubspecName.");
exit(1);
}
return Config.fromYaml(bindingsConfigMap);
}

/// Extracts configuration from a custom yaml file.
Config getConfigFromCustomYaml(String yamlPath) {
final yamlFile = File(yamlPath);

if (!yamlFile.existsSync()) {
_logger.severe('Error: $yamlPath not found.');
exit(1);
}

// Throws a [YamlException] if it's unable to parse the Yaml.
final bindingsConfigMap =
yaml.loadYaml(yamlFile.readAsStringSync()) as yaml.YamlMap;

return Config.fromYaml(bindingsConfigMap);
}

/// Parses the cmd line arguments.
ArgResults getArgResults(List<String> args) {
final parser = ArgParser(allowTrailingOptions: true);

parser.addSeparator(
'FFIGEN: Generate dart bindings from C header files\nUsage:');
parser.addOption(
'config',
help: 'path to Yaml file containing configurations if not in pubspec.yaml',
);
parser.addOption(
'verbose',
abbr: 'v',
defaultsTo: 'info',
allowed: [
'all',
'fine',
'info',
'warning',
'severe',
],
);
parser.addFlag(
'help',
abbr: 'h',
help: 'prints this usage',
negatable: false,
);

ArgResults results;
try {
results = parser.parse(args);

if (results.wasParsed('help')) {
print(parser.usage);
exit(0);
}
} catch (e) {
print(e);
print(parser.usage);
exit(1);
}

return results;
}

/// Sets up the logging level and printing.
void setupLogger(ArgResults result) {
if (result.wasParsed('verbose')) {
switch (result['verbose'] as String) {
case 'all':
// Logs everything, the entire AST touched by our parser.
Logger.root.level = Level.ALL;
break;
case 'fine':
// Logs AST parts relevant to user (i.e those included in filters).
Logger.root.level = Level.FINE;
break;
case 'info':
// Logs relevant info for general user (default).
Logger.root.level = Level.INFO;
break;
case 'warning':
// Logs warnings for relevant stuff.
Logger.root.level = Level.WARNING;
break;
case 'severe':
// Logs severe warnings and errors.
Logger.root.level = Level.SEVERE;
break;
}
// Setup logger for printing (if verbosity was set by user).
Logger.root.onRecord.listen((record) {
print('${record.level.name.padRight(8)}: ${record.message}');
});
} else {
// Setup logger for printing (if verbosity was not set by user).
Logger.root.onRecord.listen((record) {
if (record.level.value > Level.INFO.value) {
print(' ${record.level.name.padRight(8)}: ${record.message}');
} else {
print(record.message);
}
});
}
}
11 changes: 11 additions & 0 deletions example/c_json/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Files and directories created by pub.
.dart_tool/
.packages
# Remove the following pattern if you wish to check in your lock file.
pubspec.lock

# Conventional directory for build outputs.
build/

# Directory created by dartdoc.
doc/api/
25 changes: 25 additions & 0 deletions example/c_json/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# cJson example

Demonstrates generation of bindings for a C library called
[cJson](https://github.com/DaveGamble/cJSON) and then using these bindings
to parse some json.

## Building the cJson dynamic library
From the root of this repository -
```
cd third_party/cjson_library
cmake .
make
```

## Generating bindings
At the root of this example (`example/c_json`), run -
```
pub run ffigen:generate
mannprerak2 marked this conversation as resolved.
Show resolved Hide resolved
dcharkes marked this conversation as resolved.
Show resolved Hide resolved
```
This will generate bindings in a file: [cjson_generated_bindings.dart](./cjson_generated_bindings.dart)

## Running the example
```
dart main.dart
```
Loading