diff --git a/.github/workflows/test-package.yml b/.github/workflows/test-package.yml
index f9fc2b88..d3ed8c62 100644
--- a/.github/workflows/test-package.yml
+++ b/.github/workflows/test-package.yml
@@ -49,8 +49,6 @@ jobs:
run: dart pub get
- name: Install libclang-10-dev
run: sudo apt-get install libclang-10-dev
- - name: Setup ffigen
- run: dart --no-sound-null-safety run ffigen:setup
- name: Build test dylib
run: cd test/native_test && dart build_test_dylib.dart && cd ../..
- name: Run VM tests
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 67ad9482..865e28b0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 2.0.0-dev.2
+- Removed setup phase for ffigen. Added new optional config key `llvm-lib`
+to specify path to `llvm/lib` folder.
+
# 2.0.0-dev.1
- Added support for passing and returning struct by value in functions.
diff --git a/README.md b/README.md
index 2cd23d2d..15e659ad 100644
--- a/README.md
+++ b/README.md
@@ -40,13 +40,13 @@ typedef _dart_sum = int Function(int a, int b);
```
## Using this package
- Add `ffigen` under `dev_dependencies` in your `pubspec.yaml`.
-- Setup for use (see [Setup](#Setup)).
+- Install LLVM (see [Installing LLVM](#installing-llvm)).
- Configurations must be provided in `pubspec.yaml` or in a custom YAML file (see [configurations](#configurations)).
- Run the tool- `dart run ffigen`.
Jump to [FAQ](#faq).
-## Setup
+## Installing LLVM
`package:ffigen` uses LLVM. Install LLVM (9+) in the following way.
#### ubuntu/linux
@@ -87,6 +87,16 @@ The following configuration options are available-
```yaml
output: 'generated_bindings.dart'
+```
+
+
+
+ llvm-lib |
+ Path to llvm/lib folder. Required if ffigen is unable to find this at default locations. |
+
+
+```yaml
+llvm-lib: '/usr/local/opt/llvm/lib'
```
|
@@ -383,13 +393,12 @@ class ArrayHelper_CXFileUniqueID_data_level0 {
2. Run `pub run ffigen`.
## Running Tests
-1. Run setup to build the LLVM wrapper - `pub run ffigen:setup`.
-2. Dynamic library for some tests also need to be built before running the examples.
+1. Dynamic library for some tests need to be built before running the examples.
1. `cd test/native_test`.
2. Run `dart build_test_dylib.dart`.
Run tests from the root of the package with `pub run test`.
-
+> Note: If llvm is not installed in one of the default locations, tests may fail.
## FAQ
### Can ffigen be used for removing underscores or renaming declarations?
Ffigen supports **regexp based renaming**, the regexp must be a
diff --git a/bin/ffigen.dart b/bin/ffigen.dart
index 82abac5b..4405d19b 100644
--- a/bin/ffigen.dart
+++ b/bin/ffigen.dart
@@ -11,8 +11,6 @@ import 'package:ffigen/ffigen.dart';
import 'package:logging/logging.dart';
import 'package:yaml/yaml.dart' as yaml;
-import 'setup.dart';
-
final _logger = Logger('ffigen.ffigen');
final _ansi = Ansi(Ansi.terminalSupportsAnsi);
@@ -31,16 +29,6 @@ void main(List args) {
// Setup logging level and printing.
setupLogger(argResult);
- /// Prompt user if dylib doesn't exist and cannot be auto created to run
- /// `pub run ffigen:setup -Ipath/to/llvm/include -Lpath/to/llvm/lib`.
- if (!checkDylibExist() && !autoCreateDylib()) {
- _logger.severe('Unable to create dynamic library automatically.');
- _logger.severe('If LLVM (9+) is installed, try running:');
- _logger.severe(
- ' pub run ffigen:setup -Ipath/to/llvm/include -Lpath/to/llvm/lib');
- exit(1);
- }
-
// Create a config object.
Config config;
try {
diff --git a/bin/setup.dart b/bin/setup.dart
deleted file mode 100644
index edc79e21..00000000
--- a/bin/setup.dart
+++ /dev/null
@@ -1,275 +0,0 @@
-// 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.
-
-/// =======================================================================
-/// =============== Build script to generate dyamic library ===============
-/// =======================================================================
-/// This Script effectively calls the following (but user can provide
-/// command line args which will replace the defaults shown below)-
-///
-/// Linux:
-/// ```
-/// clang -I/usr/lib/llvm-9/include/ -I/usr/lib/llvm-10/include/ -lclang -shared -fpic path/to/wrapper.c -o path/to/libwrapped_clang.so
-/// ```
-/// MacOS:
-/// ```
-/// clang -I/usr/local/opt/llvm/include/ -L/usr/local/opt/llvm/lib/ -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ -v -lclang -shared -fpic path/to/wrapper.c -o path/to/libwrapped_clang.dylib
-/// ```
-/// Windows:
-/// ```
-/// clang -IC:\Progra~1\LLVM\include -LC:\Progra~1\LLVM\lib -llibclang -shared path/to/wrapper.c -o path/to/wrapped_clang.dll -Wl,/DEF:path/to/wrapper.def
-/// ```
-/// =======================================================================
-/// =======================================================================
-/// =======================================================================
-
-import 'dart:io';
-import 'package:args/args.dart';
-import 'package:ffigen/src/find_resource.dart';
-import 'package:ffigen/src/strings.dart' as strings;
-import 'package:path/path.dart' as path;
-
-/// Default platform options.
-final _linuxOpts = _Options(
- sharedFlag: '-shared',
- inputHeader: _getWrapperPath('wrapper.c'),
- fPIC: '-fpic',
- ldLibFlag: '-lclang',
- headerIncludes: [
- '-I/usr/lib/llvm-9/include/',
- '-I/usr/lib/llvm-10/include/',
- ],
-);
-final _windowsOpts = _Options(
- sharedFlag: '-shared',
- inputHeader: _getWrapperPath('wrapper.c'),
- moduleDefPath: '-Wl,/DEF:${_getWrapperPath("wrapper.def")}',
- ldLibFlag: '-llibclang',
- headerIncludes: [
- r'-IC:\Progra~1\LLVM\include',
- ],
- libIncludes: [
- r'-LC:\Progra~1\LLVM\lib',
- ],
-);
-final _macOSOpts = _Options(
- sharedFlag: '-shared',
- inputHeader: _getWrapperPath('wrapper.c'),
- fPIC: '-fpic',
- ldLibFlag: '-lclang',
- headerIncludes: [
- '-I/usr/local/opt/llvm/include/',
- '-I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/',
- ],
- libIncludes: [
- '-L/usr/local/opt/llvm/lib/',
- ],
-);
-
-/// If main is called directly we always re-create the dynamic library.
-void main(List arguments) {
- // Parses the cmd args. This will print usage and exit if --help was passed.
- final argResults = _getArgResults(arguments);
-
- print('Building Dynamic Library for libclang wrapper...');
- final options = _getPlatformOptions();
- _deleteOldDylib();
-
- // Updates header/lib includes in platform options.
- _changeIncludesUsingCmdArgs(argResults, options);
-
- // Run clang compiler to generate the dynamic library.
- final processResult = _runClangProcess(options);
- _printDetails(processResult, options);
-}
-
-/// Returns true if auto creating dylib was successful.
-///
-/// This will fail if llvm is not in default directories or if .dart_tool
-/// doesn't exist.
-bool autoCreateDylib() {
- _deleteOldDylib();
- final options = _getPlatformOptions();
- final processResult = _runClangProcess(options);
- if ((processResult.stderr as String).isNotEmpty) {
- print(processResult.stderr);
- }
- return checkDylibExist();
-}
-
-bool checkDylibExist() {
- return File(path.join(
- _getDotDartToolPath(),
- strings.ffigenFolderName,
- strings.dylibFileName,
- )).existsSync();
-}
-
-/// Removes old dynamic libraries(if any) by deleting .dart_tool/ffigen.
-///
-/// Throws error if '.dart_tool' is not found.
-void _deleteOldDylib() {
- // Find .dart_tool.
- final dtpath = _getDotDartToolPath();
- // Find .dart_tool/ffigen and delete recursively if it exists.
- final ffigenDir = Directory(path.join(dtpath, strings.ffigenFolderName));
- if (ffigenDir.existsSync()) ffigenDir.deleteSync(recursive: true);
-}
-
-/// Creates necesarry parent folders and return full path to dylib.
-String _dylibPath() {
- // Find .dart_tool.
- final dtpath = _getDotDartToolPath();
- // Create .dart_tool/ffigen if it doesn't exists.
- final ffigenDir = Directory(path.join(dtpath, strings.ffigenFolderName));
- if (!ffigenDir.existsSync()) ffigenDir.createSync();
-
- // Return dylib path
- return path.join(ffigenDir.absolute.path, strings.dylibFileName);
-}
-
-/// Returns full path of the wrapper files.
-///
-/// Throws error if not found.
-String _getWrapperPath(String wrapperName) {
- final file = File.fromUri(findWrapper(wrapperName)!);
- if (file.existsSync()) {
- return file.absolute.path;
- } else {
- throw Exception('Unable to find $wrapperName file.');
- }
-}
-
-/// Gets full path to .dart_tool.
-///
-/// Throws Exception if not found.
-String _getDotDartToolPath() {
- final dtpath = findDotDartTool()?.toFilePath();
- if (dtpath == null) {
- throw Exception('.dart_tool not found.');
- }
- return dtpath;
-}
-
-/// Calls the clang compiler.
-ProcessResult _runClangProcess(_Options options) {
- final result = Process.runSync(
- 'clang',
- [
- ...options.headerIncludes,
- ...options.libIncludes,
- options.ldLibFlag,
- options.sharedFlag,
- options.fPIC,
- options.inputHeader,
- '-o',
- _dylibPath(),
- options.moduleDefPath,
- '-Wno-nullability-completeness',
- ],
- );
- return result;
-}
-
-/// Prints success message (or process error if any).
-void _printDetails(ProcessResult result, _Options options) {
- print(result.stdout);
- if ((result.stderr as String).isNotEmpty) {
- print(result.stderr);
- } else {
- print('Created dynamic library.');
- }
-}
-
-ArgResults _getArgResults(List args) {
- final parser = ArgParser(allowTrailingOptions: true);
- parser.addSeparator('Generates LLVM Wrapper used by this package:');
- parser.addMultiOption('include-header',
- abbr: 'I', help: 'Path to header include directories');
- parser.addMultiOption('include-lib',
- abbr: 'L', help: 'Path to library include directories');
- 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;
-}
-
-/// Use cmd args(if any) to change header/lib include paths.
-void _changeIncludesUsingCmdArgs(ArgResults argResult, _Options options) {
- if (argResult.wasParsed('include-header')) {
- options.headerIncludes = (argResult['include-header'] as List)
- .map((header) => '-I$header')
- .toList();
- }
- if (argResult.wasParsed('include-lib')) {
- options.libIncludes = (argResult['include-lib'] as List)
- .map((lib) => '-L$lib')
- .toList();
- }
-}
-
-/// Get options based on current platform.
-_Options _getPlatformOptions() {
- if (Platform.isMacOS) {
- return _macOSOpts;
- } else if (Platform.isWindows) {
- return _windowsOpts;
- } else if (Platform.isLinux) {
- return _linuxOpts;
- } else {
- throw Exception('Unknown Platform.');
- }
-}
-
-/// Hold options which would be passed to clang.
-class _Options {
- /// Tells compiler to generate a shared library.
- final String sharedFlag;
-
- /// Flag for generating Position Independant Code (Not used on windows).
- final String fPIC;
-
- /// Input file.
- final String inputHeader;
-
- /// Path to `.def` file containing symbols to export, windows use only.
- final String moduleDefPath;
-
- /// Path to header files.
- List headerIncludes;
-
- /// Path to dynamic/static libraries
- List libIncludes;
-
- /// Linker flag for linking to libclang.
- final String ldLibFlag;
-
- _Options({
- required this.sharedFlag,
- required this.inputHeader,
- required this.ldLibFlag,
- this.headerIncludes = const [],
- this.libIncludes = const [],
- this.fPIC = '',
- this.moduleDefPath = '',
- });
-}
diff --git a/example/libclang-example/pubspec.yaml b/example/libclang-example/pubspec.yaml
index c1bfc6c1..e81c3269 100644
--- a/example/libclang-example/pubspec.yaml
+++ b/example/libclang-example/pubspec.yaml
@@ -15,6 +15,9 @@ ffigen:
output: 'generated_bindings.dart'
sort: true
+ # This is required if LLVM can't be found in default locations by ffigen.
+ # llvm-lib: '/usr/local/opt/llvm/lib'
+
# Bash style Glob matching is also supported.
# TODO(11): Globs dont work on windows if they begin with '.' or '..'.
headers:
diff --git a/lib/src/README.md b/lib/src/README.md
index 900c9f7f..cdfc01a7 100644
--- a/lib/src/README.md
+++ b/lib/src/README.md
@@ -2,12 +2,9 @@
## Table of Contents -
1. [Overview](#overview)
2. [LibClang](#LibClang)
- 1. [The Wrapper library](#The-Wrapper-library)
- 2. [Generation and Usage](#Generation-and-Usage)
- 3. [Bindings](#Bindings)
+ 1. [Bindings](#Bindings)
3. [Scripts](#scripts)
1. [ffigen.dart](#ffigen.dart)
- 2. [setup.dart](#setup.dart)
4. [Components](#components)
1. [Config Provider](#Config-Provider)
2. [Header Parser](#Header-Parser)
@@ -15,21 +12,7 @@
# Overview
`package:ffigen` simplifies the process of generating `dart:ffi` bindings from C header files. It is simple to use, with the input being a small YAML config file. It requires LLVM (9+) to work. This document tries to give a complete overview of every component without going into too many details about every single class/file.
# LibClang
-`package:ffigen` binds to LibClang using `dart:ffi` for parsing C header files. A wrapper library must be generated to use it, as `dart:ffi` currently [doesn't support structs by value](https://github.com/dart-lang/ffigen/issues/3).
-## The Wrapper library
-> Note: The wrapper is only needed because `dart:ffi` currently doesn't support Structs by value.
-
-The `wrapper.c` file consists of functions that wrap LibClang functions. Most of them simply convert structs by value to pointers. Except -
-- `clang_visitChildren_wrap` - The bindings for this function internally uses a **list** of **stack** for maintaining the supplied visitor functions. This is required because this function takes a function pointer which itself passes a struct by value. All this effort makes `clang_visitChildren_wrap` behave exactly like `clang_visitChildren`.
-## Generation and Usage
-The files needed for generating the wrapper are in `lib/src/clang_library`.
-> The `wrapper.def` file is only needed on windows because the symbols are otherwise hidden.
-
-The libclang wrapper can be _manually_ generated using `pub run ffigen:setup`. See [setup.dart](#setup.dart) for details.
-
-The generated file is placed in the project's `.dart_tool/ffigen` folder, the file name also specifies the ffigen version (E.g - `_v0_2_4_libclang_wrapper.dylib`), this helps ensure the correct wrapper is being used for its corresponding version.
-
-This dynamic library is then used by [Header Parser](#header-parser) for parsing C files.
+`package:ffigen` binds to LibClang using `dart:ffi` for parsing C header files.
## Bindings
The config file for generating bindings is `tool/libclang_config.yaml`. The bindings are generated to `lib/src/header_parser/clang_bindings/clang_bindings.dart`. These are used by [Header Parser](#header-parser) for calling libclang functions.
# Scripts
@@ -38,19 +21,11 @@ This is the main entry point for the user- `pub run ffigen`.
- Command-line options:
- `--verbose`: Sets log level.
- `--config`: Specifies a config file.
-- `ffigen.dart` will first check if a dynamic library already exists and is up to date. If not, it tries to auto-create it. If that fails, user must excplicitly call [setup.dart](#setup.dart).
- The internal modules are called by `ffigen.dart` in the following way:
+- `ffigen.dart` will try to find dynamic library in default locations. If that fails, the user must excplicitly specify location in ffigen's config under the key `llvm-lib`.
- It first creates a `Config` object from an input Yaml file. This is used by other modules.
- The `parse` method is then invoked to generate a `Library` object.
- Finally, the code is generated from the `Library` object to the specified file.
-## setup.dart
-Used to generate the wrapper dynamic library. Users will need to explicitly call this if `pub run ffigen` is unable to auto-create the dynamic library.
-> `clang` must be on user's path for `setup.dart` to work.
-
-- Command-line options:
- - `-I`: Specifies header includes.
- - `-L`: Specifies library includes.
-- `setup.dart` generates the dynamic library to the project's `.dart_tool/ffigen` folder using `clang`.
# Components
## Config Provider
The Config Provider holds all the configurations required by other modules.
diff --git a/lib/src/clang_library/wrapper.c b/lib/src/clang_library/wrapper.c
deleted file mode 100644
index 96f64bae..00000000
--- a/lib/src/clang_library/wrapper.c
+++ /dev/null
@@ -1,370 +0,0 @@
-// 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
-#include
-#include
-
-// utility.
-#define aloc(T) ((T *)malloc(sizeof(T)))
-CXCursor *ptrToCXCursor(CXCursor t)
-{
- CXCursor *c = aloc(CXCursor);
- *c = t;
- return c;
-}
-CXString *ptrToCXString(CXString t)
-{
- CXString *c = aloc(CXString);
- *c = t;
- return c;
-}
-CXType *ptrToCXType(CXType t)
-{
- CXType *c = aloc(CXType);
- *c = t;
- return c;
-}
-CXSourceLocation *ptrToCXSourceLocation(CXSourceLocation t)
-{
- CXSourceLocation *c = aloc(CXSourceLocation);
- *c = t;
- return c;
-}
-CXSourceRange *ptrToCXSourceRange(CXSourceRange t)
-{
- CXSourceRange *c = aloc(CXSourceRange);
- *c = t;
- return c;
-}
-// START ===== Functions for testing libclang behavior in C.
-enum CXChildVisitResult visitor_for_test_in_c(CXCursor cursor, CXCursor parent, CXClientData clientData)
-{
- printf("Cursor- kind: %s, name: %s\n", clang_getCString(clang_getCursorKindSpelling(clang_getCursorKind(cursor))), clang_getCString(clang_getCursorSpelling(cursor)));
- return CXChildVisit_Continue;
-}
-int test_in_c()
-{
- printf("==========================run==========================\n");
- CXIndex Index = clang_createIndex(0, 0);
- CXTranslationUnit TU = clang_parseTranslationUnit(Index,
- "./test.h", 0, 0, NULL, 0, CXTranslationUnit_None);
-
- if (TU == NULL)
- {
- printf("Error creating TU\n");
- return 0;
- }
-
- CXCursor root = clang_getTranslationUnitCursor(TU);
-
- unsigned a = clang_visitChildren(root, visitor_for_test_in_c, NULL);
-
- clang_disposeTranslationUnit(TU);
- clang_disposeIndex(Index);
- printf("\n==========================end==========================\n");
- return 0;
-}
-// END ===== Functions for testing libclang behavior in C ============================
-
-// START ===== WRAPPER FUNCTIONS =====================
-
-const char *clang_getCString_wrap(CXString *string)
-{
- const char *a = clang_getCString(*string);
-
- return a;
-}
-
-void clang_disposeString_wrap(CXString *string)
-{
- clang_disposeString(*string);
- free(string);
- return;
-}
-
-enum CXCursorKind clang_getCursorKind_wrap(CXCursor *cursor)
-{
- return clang_getCursorKind(*cursor);
-}
-
-CXString *clang_getCursorKindSpelling_wrap(enum CXCursorKind kind)
-{
- return ptrToCXString(clang_getCursorKindSpelling(kind));
-}
-
-CXType *clang_getCursorType_wrap(CXCursor *cursor)
-{
- return ptrToCXType(clang_getCursorType(*cursor));
-}
-
-CXString *clang_getTypeSpelling_wrap(CXType *type)
-{
- return ptrToCXString(clang_getTypeSpelling(*type));
-}
-
-CXString *clang_getTypeKindSpelling_wrap(enum CXTypeKind typeKind)
-{
- return ptrToCXString(clang_getTypeKindSpelling(typeKind));
-}
-
-CXType *clang_getResultType_wrap(CXType *functionType)
-{
- return ptrToCXType(clang_getResultType(*functionType));
-}
-
-CXType *clang_getPointeeType_wrap(CXType *pointerType)
-{
- return ptrToCXType(clang_getPointeeType(*pointerType));
-}
-
-CXType *clang_getCanonicalType_wrap(CXType *typerefType)
-{
- return ptrToCXType(clang_getCanonicalType(*typerefType));
-}
-
-CXType *clang_Type_getNamedType_wrap(CXType *elaboratedType)
-{
- return ptrToCXType(clang_Type_getNamedType(*elaboratedType));
-}
-
-CXCursor *clang_getTypeDeclaration_wrap(CXType *cxtype)
-{
- return ptrToCXCursor(clang_getTypeDeclaration(*cxtype));
-}
-
-CXType *clang_getTypedefDeclUnderlyingType_wrap(CXCursor *cxcursor)
-{
- return ptrToCXType(clang_getTypedefDeclUnderlyingType(*cxcursor));
-}
-
-/** The name of parameter, struct, typedef. */
-CXString *clang_getCursorSpelling_wrap(CXCursor *cursor)
-{
- return ptrToCXString(clang_getCursorSpelling(*cursor));
-}
-
-CXCursor *clang_getTranslationUnitCursor_wrap(CXTranslationUnit tu)
-{
- return ptrToCXCursor(clang_getTranslationUnitCursor(tu));
-}
-
-CXString *clang_formatDiagnostic_wrap(CXDiagnostic diag, int opts)
-{
- return ptrToCXString(clang_formatDiagnostic(diag, opts));
-}
-
-// Alternative typedef for [CXCursorVisitor] using pointer for passing cursor and parent
-// instead of passing by value
-typedef enum CXChildVisitResult (*ModifiedCXCursorVisitor)(CXCursor *cursor,
- CXCursor *parent,
- CXClientData client_data);
-
-struct _stackForVisitChildren
-{
- ModifiedCXCursorVisitor modifiedVisitor;
- struct _stackForVisitChildren *link;
-} * _visitorTemp;
-
-// Holds list of Isolate-Processor pairs, each having their own stack
-// to hold the vistorFunctions.
-struct _listForIsolateProcessPair
-{
- long long uid;
- struct _listForIsolateProcessPair *next;
- struct _stackForVisitChildren *_visitorTop;
-} ipHead, *ipTemp;
-// `ipHead` is used only as head marker and will not contain any information.
-
-// Finds/Creates an Isolate-Processor pair from/in the linkedlist.
-struct _listForIsolateProcessPair *_findIP(long long uid)
-{
- struct _listForIsolateProcessPair *temp = ipHead.next;
- while (temp != NULL)
- {
- if (temp->uid == uid)
- {
- return temp;
- }
- temp = temp->next;
- }
- // If we reach here this means no IP pair was found and we should create one
- // and add it to the head of our list.
- temp = aloc(struct _listForIsolateProcessPair);
- temp->next = ipHead.next;
- temp->uid = uid;
- temp->_visitorTop = NULL;
- ipHead.next = temp;
- return temp;
-}
-void _push(ModifiedCXCursorVisitor modifiedVisitor, long long uid)
-{
- struct _listForIsolateProcessPair *current = _findIP(uid);
- if (current->_visitorTop == NULL)
- {
- current->_visitorTop = aloc(struct _stackForVisitChildren);
- current->_visitorTop->link = NULL;
- current->_visitorTop->modifiedVisitor = modifiedVisitor;
- }
- else
- {
- _visitorTemp = aloc(struct _stackForVisitChildren);
- _visitorTemp->link = current->_visitorTop;
- _visitorTemp->modifiedVisitor = modifiedVisitor;
- current->_visitorTop = _visitorTemp;
- }
-}
-void _pop(long long uid)
-{
- struct _listForIsolateProcessPair *current = _findIP(uid);
- _visitorTemp = current->_visitorTop;
-
- if (_visitorTemp == NULL)
- {
- printf("\n Error, Wrapper.C : Trying to pop from empty stack");
- return;
- }
- else
- _visitorTemp = current->_visitorTop->link;
- free(current->_visitorTop);
- current->_visitorTop = _visitorTemp;
-}
-ModifiedCXCursorVisitor _top(long long uid)
-{
- return _findIP(uid)->_visitorTop->modifiedVisitor;
-}
-
-// Do not write binding for this function.
-// used by [clang_visitChildren_wrap].
-enum CXChildVisitResult
-_visitorwrap(CXCursor cursor, CXCursor parent, CXClientData clientData)
-{
- // Use clientData (which is a unique ID) to get reference to the stack which
- // this particular process-isolate pair uses.
- long long uid = *((long long *)clientData);
- enum CXChildVisitResult e = (_top(uid)(ptrToCXCursor(cursor), ptrToCXCursor(parent), clientData));
- return e;
-}
-
-/** Visitor is a function pointer with parameters having pointers to cxcursor
-* instead of cxcursor by default. */
-unsigned clang_visitChildren_wrap(CXCursor *parent, ModifiedCXCursorVisitor _modifiedVisitor, long long uid)
-{
- long long *clientData = aloc(long long);
- *clientData = uid;
- _push(_modifiedVisitor, uid);
- unsigned a = clang_visitChildren(*parent, _visitorwrap, clientData);
- _pop(uid);
- return a;
-}
-
-int clang_Cursor_getNumArguments_wrap(CXCursor *cursor)
-{
- return clang_Cursor_getNumArguments(*cursor);
-}
-
-CXCursor *clang_Cursor_getArgument_wrap(CXCursor *cursor, unsigned i)
-{
- return ptrToCXCursor(clang_Cursor_getArgument(*cursor, i));
-}
-
-int clang_getNumArgTypes_wrap(CXType *cxtype)
-{
- return clang_getNumArgTypes(*cxtype);
-}
-
-CXType *clang_getArgType_wrap(CXType *cxtype, unsigned i)
-{
- return ptrToCXType(clang_getArgType(*cxtype, i));
-}
-
-long long clang_getEnumConstantDeclValue_wrap(CXCursor *cursor)
-{
- return clang_getEnumConstantDeclValue(*cursor);
-}
-
-/** Returns non-zero if the ranges are the same, zero if they differ. */
-unsigned clang_equalRanges_wrap(CXSourceRange *c1, CXSourceRange *c2)
-{
- return clang_equalRanges(*c1, *c2);
-}
-
-/** Returns the comment range. */
-CXSourceRange *clang_Cursor_getCommentRange_wrap(CXCursor *cursor)
-{
- return ptrToCXSourceRange(clang_Cursor_getCommentRange(*cursor));
-}
-
-/** Returns the raw comment. */
-CXString *clang_Cursor_getRawCommentText_wrap(CXCursor *cursor)
-{
- return ptrToCXString(clang_Cursor_getRawCommentText(*cursor));
-}
-
-/** Returns the first paragraph of doxygen doc comment. */
-CXString *clang_Cursor_getBriefCommentText_wrap(CXCursor *cursor)
-{
- return ptrToCXString(clang_Cursor_getBriefCommentText(*cursor));
-}
-
-CXSourceLocation *clang_getCursorLocation_wrap(CXCursor *cursor)
-{
- return ptrToCXSourceLocation(clang_getCursorLocation(*cursor));
-}
-
-void clang_getFileLocation_wrap(CXSourceLocation *location, CXFile *file, unsigned *line, unsigned *column, unsigned *offset)
-{
- return clang_getFileLocation(*location, file, line, column, offset);
-}
-
-CXString *clang_getFileName_wrap(CXFile SFile)
-{
- return ptrToCXString(clang_getFileName(SFile));
-}
-
-unsigned long long clang_getNumElements_wrap(CXType *cxtype)
-{
- return clang_getNumElements(*cxtype);
-}
-
-CXType *clang_getArrayElementType_wrap(CXType *cxtype)
-{
- return ptrToCXType(clang_getArrayElementType(*cxtype));
-}
-
-unsigned clang_Cursor_isMacroFunctionLike_wrap(CXCursor *cursor)
-{
- return clang_Cursor_isMacroFunctionLike(*cursor);
-}
-
-unsigned clang_Cursor_isMacroBuiltin_wrap(CXCursor *cursor)
-{
- return clang_Cursor_isMacroBuiltin(*cursor);
-}
-
-CXEvalResult clang_Cursor_Evaluate_wrap(CXCursor *cursor)
-{
- return clang_Cursor_Evaluate(*cursor);
-}
-
-unsigned clang_Cursor_isAnonymous_wrap(CXCursor *cursor)
-{
- return clang_Cursor_isAnonymous(*cursor);
-}
-
-unsigned clang_Cursor_isAnonymousRecordDecl_wrap(CXCursor *cursor)
-{
- return clang_Cursor_isAnonymousRecordDecl(*cursor);
-}
-
-CXString *clang_getCursorUSR_wrap(CXCursor *cursor)
-{
- return ptrToCXString(clang_getCursorUSR(*cursor));
-}
-
-int clang_getFieldDeclBitWidth_wrap(CXCursor *cursor){
- return clang_getFieldDeclBitWidth(*cursor);
-}
-
-// END ===== WRAPPER FUNCTIONS =====================
diff --git a/lib/src/clang_library/wrapper.def b/lib/src/clang_library/wrapper.def
deleted file mode 100644
index 8a984b02..00000000
--- a/lib/src/clang_library/wrapper.def
+++ /dev/null
@@ -1,362 +0,0 @@
-; 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.
-
-EXPORTS
-clang_getCString
-clang_disposeString
-clang_disposeStringSet
-clang_createIndex
-clang_disposeIndex
-clang_CXIndex_setGlobalOptions
-clang_CXIndex_getGlobalOptions
-clang_CXIndex_setInvocationEmissionPathOption
-clang_getFileName
-clang_getFileTime
-clang_getFileUniqueID
-clang_isFileMultipleIncludeGuarded
-clang_getFile
-clang_getFileContents
-clang_File_isEqual
-clang_File_tryGetRealPathName
-clang_getNullLocation
-clang_equalLocations
-clang_getLocation
-clang_getLocationForOffset
-clang_Location_isInSystemHeader
-clang_Location_isFromMainFile
-clang_getNullRange
-clang_getRange
-clang_equalRanges
-clang_Range_isNull
-clang_getExpansionLocation
-clang_getPresumedLocation
-clang_getInstantiationLocation
-clang_getSpellingLocation
-clang_getFileLocation
-clang_getRangeStart
-clang_getRangeEnd
-clang_getSkippedRanges
-clang_getAllSkippedRanges
-clang_disposeSourceRangeList
-clang_getNumDiagnosticsInSet
-clang_getDiagnosticInSet
-clang_loadDiagnostics
-clang_disposeDiagnosticSet
-clang_getChildDiagnostics
-clang_getNumDiagnostics
-clang_getDiagnostic
-clang_getDiagnosticSetFromTU
-clang_disposeDiagnostic
-clang_formatDiagnostic
-clang_defaultDiagnosticDisplayOptions
-clang_getDiagnosticSeverity
-clang_getDiagnosticLocation
-clang_getDiagnosticSpelling
-clang_getDiagnosticOption
-clang_getDiagnosticCategory
-clang_getDiagnosticCategoryName
-clang_getDiagnosticCategoryText
-clang_getDiagnosticNumRanges
-clang_getDiagnosticRange
-clang_getDiagnosticNumFixIts
-clang_getDiagnosticFixIt
-clang_getTranslationUnitSpelling
-clang_createTranslationUnitFromSourceFile
-clang_createTranslationUnit
-clang_createTranslationUnit2
-clang_defaultEditingTranslationUnitOptions
-clang_parseTranslationUnit
-clang_parseTranslationUnit2
-clang_parseTranslationUnit2FullArgv
-clang_defaultSaveOptions
-clang_saveTranslationUnit
-clang_suspendTranslationUnit
-clang_disposeTranslationUnit
-clang_defaultReparseOptions
-clang_reparseTranslationUnit
-clang_getTUResourceUsageName
-clang_getCXTUResourceUsage
-clang_disposeCXTUResourceUsage
-clang_getTranslationUnitTargetInfo
-clang_TargetInfo_dispose
-clang_TargetInfo_getTriple
-clang_TargetInfo_getPointerWidth
-clang_getNullCursor
-clang_getTranslationUnitCursor
-clang_equalCursors
-clang_Cursor_isNull
-clang_hashCursor
-clang_getCursorKind
-clang_isDeclaration
-clang_isInvalidDeclaration
-clang_isReference
-clang_isExpression
-clang_isStatement
-clang_isAttribute
-clang_Cursor_hasAttrs
-clang_isInvalid
-clang_isTranslationUnit
-clang_isPreprocessing
-clang_isUnexposed
-clang_getCursorLinkage
-clang_getCursorVisibility
-clang_getCursorAvailability
-clang_getCursorPlatformAvailability
-clang_disposeCXPlatformAvailability
-clang_getCursorLanguage
-clang_getCursorTLSKind
-clang_Cursor_getTranslationUnit
-clang_createCXCursorSet
-clang_disposeCXCursorSet
-clang_CXCursorSet_contains
-clang_CXCursorSet_insert
-clang_getCursorSemanticParent
-clang_getCursorLexicalParent
-clang_getOverriddenCursors
-clang_disposeOverriddenCursors
-clang_getIncludedFile
-clang_getCursor
-clang_getCursorLocation
-clang_getCursorExtent
-clang_getCursorType
-clang_getTypeSpelling
-clang_getTypedefDeclUnderlyingType
-clang_getEnumDeclIntegerType
-clang_getEnumConstantDeclValue
-clang_getEnumConstantDeclUnsignedValue
-clang_getFieldDeclBitWidth
-clang_Cursor_getNumArguments
-clang_Cursor_getArgument
-clang_Cursor_getNumTemplateArguments
-clang_Cursor_getTemplateArgumentKind
-clang_Cursor_getTemplateArgumentType
-clang_Cursor_getTemplateArgumentValue
-clang_Cursor_getTemplateArgumentUnsignedValue
-clang_equalTypes
-clang_getCanonicalType
-clang_isConstQualifiedType
-clang_Cursor_isMacroFunctionLike
-clang_Cursor_isMacroBuiltin
-clang_Cursor_isFunctionInlined
-clang_isVolatileQualifiedType
-clang_isRestrictQualifiedType
-clang_getAddressSpace
-clang_getTypedefName
-clang_getPointeeType
-clang_getTypeDeclaration
-clang_getDeclObjCTypeEncoding
-clang_Type_getObjCEncoding
-clang_getTypeKindSpelling
-clang_getFunctionTypeCallingConv
-clang_getResultType
-clang_getExceptionSpecificationType
-clang_getNumArgTypes
-clang_getArgType
-clang_Type_getObjCObjectBaseType
-clang_Type_getNumObjCProtocolRefs
-clang_Type_getObjCProtocolDecl
-clang_Type_getNumObjCTypeArgs
-clang_Type_getObjCTypeArg
-clang_isFunctionTypeVariadic
-clang_getCursorResultType
-clang_getCursorExceptionSpecificationType
-clang_isPODType
-clang_getElementType
-clang_getNumElements
-clang_getArrayElementType
-clang_getArraySize
-clang_Type_getNamedType
-clang_Type_isTransparentTagTypedef
-clang_Type_getNullability
-clang_Type_getAlignOf
-clang_Type_getClassType
-clang_Type_getSizeOf
-clang_Type_getOffsetOf
-clang_Type_getModifiedType
-clang_Cursor_getOffsetOfField
-clang_Cursor_isAnonymous
-clang_Cursor_isAnonymousRecordDecl
-clang_Cursor_isInlineNamespace
-clang_Type_getNumTemplateArguments
-clang_Type_getTemplateArgumentAsType
-clang_Type_getCXXRefQualifier
-clang_Cursor_isBitField
-clang_isVirtualBase
-clang_getCXXAccessSpecifier
-clang_Cursor_getStorageClass
-clang_getNumOverloadedDecls
-clang_getOverloadedDecl
-clang_getIBOutletCollectionType
-clang_visitChildren
-clang_getCursorUSR
-clang_constructUSR_ObjCClass
-clang_constructUSR_ObjCCategory
-clang_constructUSR_ObjCProtocol
-clang_constructUSR_ObjCIvar
-clang_constructUSR_ObjCMethod
-clang_constructUSR_ObjCProperty
-clang_getCursorSpelling
-clang_Cursor_getSpellingNameRange
-clang_PrintingPolicy_getProperty
-clang_PrintingPolicy_setProperty
-clang_getCursorPrintingPolicy
-clang_PrintingPolicy_dispose
-clang_getCursorPrettyPrinted
-clang_getCursorDisplayName
-clang_getCursorReferenced
-clang_getCursorDefinition
-clang_isCursorDefinition
-clang_getCanonicalCursor
-clang_Cursor_getObjCSelectorIndex
-clang_Cursor_isDynamicCall
-clang_Cursor_getReceiverType
-clang_Cursor_getObjCPropertyAttributes
-clang_Cursor_getObjCPropertyGetterName
-clang_Cursor_getObjCPropertySetterName
-clang_Cursor_getObjCDeclQualifiers
-clang_Cursor_isObjCOptional
-clang_Cursor_isVariadic
-clang_Cursor_isExternalSymbol
-clang_Cursor_getCommentRange
-clang_Cursor_getRawCommentText
-clang_Cursor_getBriefCommentText
-clang_Cursor_getMangling
-clang_Cursor_getCXXManglings
-clang_Cursor_getObjCManglings
-clang_Cursor_getModule
-clang_getModuleForFile
-clang_Module_getASTFile
-clang_Module_getParent
-clang_Module_getName
-clang_Module_getFullName
-clang_Module_isSystem
-clang_Module_getNumTopLevelHeaders
-clang_Module_getTopLevelHeader
-clang_CXXConstructor_isConvertingConstructor
-clang_CXXConstructor_isCopyConstructor
-clang_CXXConstructor_isDefaultConstructor
-clang_CXXConstructor_isMoveConstructor
-clang_CXXField_isMutable
-clang_CXXMethod_isDefaulted
-clang_CXXMethod_isPureVirtual
-clang_CXXMethod_isStatic
-clang_CXXMethod_isVirtual
-clang_CXXRecord_isAbstract
-clang_EnumDecl_isScoped
-clang_CXXMethod_isConst
-clang_getTemplateCursorKind
-clang_getSpecializedCursorTemplate
-clang_getCursorReferenceNameRange
-clang_getToken
-clang_getTokenKind
-clang_getTokenSpelling
-clang_getTokenLocation
-clang_getTokenExtent
-clang_tokenize
-clang_annotateTokens
-clang_disposeTokens
-clang_getCursorKindSpelling
-clang_getDefinitionSpellingAndExtent
-clang_enableStackTraces
-clang_executeOnThread
-clang_getCompletionChunkKind
-clang_getCompletionChunkText
-clang_getCompletionChunkCompletionString
-clang_getNumCompletionChunks
-clang_getCompletionPriority
-clang_getCompletionAvailability
-clang_getCompletionNumAnnotations
-clang_getCompletionAnnotation
-clang_getCompletionParent
-clang_getCompletionBriefComment
-clang_getCursorCompletionString
-clang_getCompletionNumFixIts
-clang_getCompletionFixIt
-clang_defaultCodeCompleteOptions
-clang_codeCompleteAt
-clang_sortCodeCompletionResults
-clang_disposeCodeCompleteResults
-clang_codeCompleteGetNumDiagnostics
-clang_codeCompleteGetDiagnostic
-clang_codeCompleteGetContexts
-clang_codeCompleteGetContainerKind
-clang_codeCompleteGetContainerUSR
-clang_codeCompleteGetObjCSelector
-clang_getClangVersion
-clang_toggleCrashRecovery
-clang_getInclusions
-clang_Cursor_Evaluate
-clang_EvalResult_getKind
-clang_EvalResult_getAsInt
-clang_EvalResult_getAsLongLong
-clang_EvalResult_isUnsignedInt
-clang_EvalResult_getAsUnsigned
-clang_EvalResult_getAsDouble
-clang_EvalResult_getAsStr
-clang_EvalResult_dispose
-clang_getRemappings
-clang_getRemappingsFromFileList
-clang_remap_getNumFiles
-clang_remap_getFilenames
-clang_remap_dispose
-clang_findReferencesInFile
-clang_findIncludesInFile
-clang_index_isEntityObjCContainerKind
-clang_index_getObjCContainerDeclInfo
-clang_index_getObjCInterfaceDeclInfo
-clang_index_getObjCCategoryDeclInfo
-clang_index_getObjCProtocolRefListInfo
-clang_index_getObjCPropertyDeclInfo
-clang_index_getIBOutletCollectionAttrInfo
-clang_index_getCXXClassDeclInfo
-clang_index_getClientContainer
-clang_index_setClientContainer
-clang_index_getClientEntity
-clang_index_setClientEntity
-clang_IndexAction_create
-clang_IndexAction_dispose
-clang_indexSourceFile
-clang_indexSourceFileFullArgv
-clang_indexTranslationUnit
-clang_indexLoc_getFileLocation
-clang_indexLoc_getCXSourceLocation
-clang_Type_visitFields
-clang_getCString_wrap
-clang_disposeString_wrap
-clang_getCursorKind_wrap
-clang_getCursorKindSpelling_wrap
-clang_getCursorType_wrap
-clang_getTypeSpelling_wrap
-clang_getTypeKindSpelling_wrap
-clang_getResultType_wrap
-clang_getPointeeType_wrap
-clang_getCanonicalType_wrap
-clang_Type_getNamedType_wrap
-clang_getTypeDeclaration_wrap
-clang_getTypedefDeclUnderlyingType_wrap
-clang_getCursorSpelling_wrap
-clang_getTranslationUnitCursor_wrap
-clang_formatDiagnostic_wrap
-clang_visitChildren_wrap
-clang_Cursor_getNumArguments_wrap
-clang_Cursor_getArgument_wrap
-clang_getNumArgTypes_wrap
-clang_getArgType_wrap
-clang_getEnumConstantDeclValue_wrap
-clang_equalRanges_wrap
-clang_Cursor_getCommentRange_wrap
-clang_Cursor_getRawCommentText_wrap
-clang_Cursor_getBriefCommentText_wrap
-clang_getCursorLocation_wrap
-clang_getFileLocation_wrap
-clang_getFileName_wrap
-clang_getNumElements_wrap
-clang_getArrayElementType_wrap
-clang_Cursor_isMacroFunctionLike_wrap
-clang_Cursor_isMacroBuiltin_wrap
-clang_Cursor_Evaluate_wrap
-clang_Cursor_isAnonymous_wrap
-clang_Cursor_isAnonymousRecordDecl_wrap
-clang_getCursorUSR_wrap
-clang_getFieldDeclBitWidth_wrap
diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart
index 0649de57..96ca643d 100644
--- a/lib/src/config_provider/config.dart
+++ b/lib/src/config_provider/config.dart
@@ -20,6 +20,10 @@ final _logger = Logger('ffigen.config_provider.config');
///
/// Handles validation, extraction of confiurations from yaml file.
class Config {
+ /// Location for llvm/lib folder.
+ String get libclangDylib => _libclangDylib;
+ late String _libclangDylib;
+
/// output file name.
String get output => _output;
late String _output;
@@ -156,6 +160,13 @@ class Config {
/// Key: Name, Value: [Specification]
Map _getSpecs() {
return {
+ strings.llvmLib: Specification(
+ requirement: Requirement.no,
+ validator: llvmLibValidator,
+ extractor: llvmLibExtractor,
+ defaultValue: () => findDylibAtDefaultLocations(),
+ extractedResult: (dynamic result) => _libclangDylib = result as String,
+ ),
strings.output: Specification(
requirement: Requirement.yes,
validator: outputValidator,
diff --git a/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart
index 2df79391..839333ae 100644
--- a/lib/src/config_provider/spec_utils.dart
+++ b/lib/src/config_provider/spec_utils.dart
@@ -197,6 +197,64 @@ String getDylibPath(String dylibParentFoler) {
return dylibPath;
}
+/// Returns location of dynamic library by searching default locations. Logs
+/// error and exits if not found.
+String findDylibAtDefaultLocations() {
+ String? k;
+ if (Platform.isLinux) {
+ for (final l in strings.linuxDylibLocations) {
+ k = findLibclangDylib(l);
+ if (k != null) return k;
+ }
+ } else if (Platform.isWindows) {
+ for (final l in strings.windowsDylibLocations) {
+ k = findLibclangDylib(l);
+ if (k != null) return k;
+ }
+ } else if (Platform.isMacOS) {
+ for (final l in strings.macOsDylibLocations) {
+ k = findLibclangDylib(l);
+ if (k != null) return k;
+ }
+ } else {
+ throw Exception('Unsupported Platform.');
+ }
+
+ _logger.severe("Couldn't find dynamic library in default locations.");
+ _logger.severe(
+ "Please supply the path/to/llvm/lib in ffigen's config under the key 'llvm-lib'.");
+ throw Exception("Couldn't find dynamic library in default locations.");
+}
+
+String? findLibclangDylib(String parentFolder) {
+ final location = p.join(parentFolder, strings.dylibFileName);
+ if (File(location).existsSync()) {
+ return location;
+ } else {
+ return null;
+ }
+}
+
+String llvmLibExtractor(dynamic value) {
+ // Extract libclang's dylib from this.
+ final p = findLibclangDylib(value as String);
+ if (p == null) {
+ _logger.severe("Couldn't find ${strings.dylibFileName} at $value.");
+ exit(1);
+ } else {
+ return p;
+ }
+}
+
+bool llvmLibValidator(String name, dynamic value) {
+ if (!checkType([name], value) ||
+ !Directory(value as String).existsSync()) {
+ _logger.severe('Expected $name to be a valid folder Path.');
+ return false;
+ }
+ return true;
+}
+
String outputExtractor(dynamic value) => _replaceSeparators(value as String);
bool outputValidator(String name, dynamic value) =>
diff --git a/lib/src/find_resource.dart b/lib/src/find_resource.dart
deleted file mode 100644
index c16d47ff..00000000
--- a/lib/src/find_resource.dart
+++ /dev/null
@@ -1,96 +0,0 @@
-// 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.
-
-import 'dart:convert' show jsonDecode;
-import 'dart:io' show File, Directory;
-
-import 'package:logging/logging.dart';
-import 'package:yaml/yaml.dart';
-
-final _logger = Logger('ffigen.find_resource');
-
-/// Find the `.dart_tool/` folder, returns `null` if unable to find it.
-Uri? findDotDartTool() {
- // HACK: Because 'dart:isolate' is unavailable in Flutter we have no means
- // by which we can find the location of the package_config.json file.
- // Which we need, because the binary library created by:
- // flutter pub run ffigen:setup
- // is located relative to this path. As a workaround we use
- // `Platform.script` and traverse level-up until we find a
- // `.dart_tool/package_config.json` file.
- // Find script directory
- var root = Directory.current.uri;
- // Traverse up until we see a `.dart_tool/package_config.json` file.
- do {
- if (File.fromUri(root.resolve('.dart_tool/package_config.json'))
- .existsSync()) {
- return root.resolve('.dart_tool/');
- }
- } while (root != (root = root.resolve('..')));
- return null;
-}
-
-/// Get [Uri] for [posixPath] inside ffigen's rootUri.
-Uri? _findInPackageRoot(String posixPath) {
- var root = Directory.current.uri;
- // Traverse up until we see a `.dart_tool/package_config.json` file.
- do {
- final file = File.fromUri(root.resolve('.dart_tool/package_config.json'));
- if (file.existsSync()) {
- /// Read the package_config.json file to extract path of wrapper.
- try {
- final packageMap =
- jsonDecode(file.readAsStringSync()) as Map;
- if (packageMap['configVersion'] == 2) {
- var ffigenRootUriString = ((packageMap['packages'] as List)
- .cast