Support for Prefix and Names in config. (#20)

- Support for global prefix and prefix replacement in functions/structs/enums
- Handles all internal name collisions (such as those between - dylib identifier, ffi import prefix, any typedefs generated, array helper classes, expanded array items, declarations, init function) if a collision occurs its suffixed by `_cr<int>`
- Added tests for prefixing and collisions
diff --git a/example/c_json/cjson_generated_bindings.dart b/example/c_json/cjson_generated_bindings.dart
index 1cf00a3..e26ed6a 100644
--- a/example/c_json/cjson_generated_bindings.dart
+++ b/example/c_json/cjson_generated_bindings.dart
@@ -7,8 +7,8 @@
 ffi.DynamicLibrary _dylib;
 
 /// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib) {
-  _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary) {
+  _dylib = dynamicLibrary;
 }
 
 class cJSON extends ffi.Struct {
@@ -32,18 +32,18 @@
   ffi.Pointer<ffi.Int8> string;
 }
 
-typedef _typedefC_noname_1 = ffi.Pointer<ffi.Void> Function(
+typedef _typedefC_1 = ffi.Pointer<ffi.Void> Function(
   ffi.Uint64,
 );
 
-typedef _typedefC_noname_2 = ffi.Void Function(
+typedef _typedefC_2 = ffi.Void Function(
   ffi.Pointer<ffi.Void>,
 );
 
 class cJSON_Hooks extends ffi.Struct {
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_1>> malloc_fn;
+  ffi.Pointer<ffi.NativeFunction<_typedefC_1>> malloc_fn;
 
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_2>> free_fn;
+  ffi.Pointer<ffi.NativeFunction<_typedefC_2>> free_fn;
 }
 
 ffi.Pointer<ffi.Int8> cJSON_Version() {
diff --git a/example/libclang-example/generated_bindings.dart b/example/libclang-example/generated_bindings.dart
index 4fbfac3..6a0d1d3 100644
--- a/example/libclang-example/generated_bindings.dart
+++ b/example/libclang-example/generated_bindings.dart
@@ -1,14 +1,15 @@
 /// AUTO GENERATED FILE, DO NOT EDIT.
 ///
 /// Generated by `package:ffigen`.
+
 import 'dart:ffi' as ffi;
 
 /// Holds the Dynamic library.
 ffi.DynamicLibrary _dylib;
 
 /// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib) {
-  _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary) {
+  _dylib = dynamicLibrary;
 }
 
 /// Contains the results of code-completion.
@@ -67,9 +68,9 @@
   @ffi.Int32()
   int xdata;
 
-  ffi.Pointer<ffi.Void> _data_item_0;
-  ffi.Pointer<ffi.Void> _data_item_1;
-  ffi.Pointer<ffi.Void> _data_item_2;
+  ffi.Pointer<ffi.Void> _exp_workaround_data_item_0;
+  ffi.Pointer<ffi.Void> _exp_workaround_data_item_1;
+  ffi.Pointer<ffi.Void> _exp_workaround_data_item_2;
 
   /// Helper for array `data`.
   ArrayHelper_CXCursor_data_level0 get data =>
@@ -96,11 +97,11 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        return _struct._data_item_0;
+        return _struct._exp_workaround_data_item_0;
       case 1:
-        return _struct._data_item_1;
+        return _struct._exp_workaround_data_item_1;
       case 2:
-        return _struct._data_item_2;
+        return _struct._exp_workaround_data_item_2;
       default:
         throw Exception('Invalid Array Helper generated.');
     }
@@ -110,13 +111,13 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        _struct._data_item_0 = value;
+        _struct._exp_workaround_data_item_0 = value;
         break;
       case 1:
-        _struct._data_item_1 = value;
+        _struct._exp_workaround_data_item_1 = value;
         break;
       case 2:
-        _struct._data_item_2 = value;
+        _struct._exp_workaround_data_item_2 = value;
         break;
       default:
         throw Exception('Invalid Array Helper generated.');
@@ -124,34 +125,19 @@
   }
 }
 
-class CXCursorAndRangeVisitor extends ffi.Struct {
-  ffi.Pointer<ffi.Void> context;
-
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_2>> visit;
-}
+class CXCursorAndRangeVisitor extends ffi.Struct {}
 
 class CXCursorSetImpl extends ffi.Struct {}
 
-typedef CXCursorVisitor = ffi.Int32 Function(
-  CXCursor,
-  CXCursor,
-  ffi.Pointer<ffi.Void>,
-);
-
-typedef CXFieldVisitor = ffi.Int32 Function(
-  CXCursor,
-  ffi.Pointer<ffi.Void>,
-);
-
 /// Uniquely identifies a CXFile, that refers to the same underlying file,
 /// across an indexing session.
 class CXFileUniqueID extends ffi.Struct {
   @ffi.Uint64()
-  int _data_item_0;
+  int _exp_workaround_data_item_0;
   @ffi.Uint64()
-  int _data_item_1;
+  int _exp_workaround_data_item_1;
   @ffi.Uint64()
-  int _data_item_2;
+  int _exp_workaround_data_item_2;
 
   /// Helper for array `data`.
   ArrayHelper_CXFileUniqueID_data_level0 get data =>
@@ -178,11 +164,11 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        return _struct._data_item_0;
+        return _struct._exp_workaround_data_item_0;
       case 1:
-        return _struct._data_item_1;
+        return _struct._exp_workaround_data_item_1;
       case 2:
-        return _struct._data_item_2;
+        return _struct._exp_workaround_data_item_2;
       default:
         throw Exception('Invalid Array Helper generated.');
     }
@@ -192,13 +178,13 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        _struct._data_item_0 = value;
+        _struct._exp_workaround_data_item_0 = value;
         break;
       case 1:
-        _struct._data_item_1 = value;
+        _struct._exp_workaround_data_item_1 = value;
         break;
       case 2:
-        _struct._data_item_2 = value;
+        _struct._exp_workaround_data_item_2 = value;
         break;
       default:
         throw Exception('Invalid Array Helper generated.');
@@ -261,8 +247,8 @@
 
 /// Source location passed to index callbacks.
 class CXIdxLoc extends ffi.Struct {
-  ffi.Pointer<ffi.Void> _ptr_data_item_0;
-  ffi.Pointer<ffi.Void> _ptr_data_item_1;
+  ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_0;
+  ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_1;
 
   /// Helper for array `ptr_data`.
   ArrayHelper_CXIdxLoc_ptr_data_level0 get ptr_data =>
@@ -291,9 +277,9 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        return _struct._ptr_data_item_0;
+        return _struct._exp_workaround_ptr_data_item_0;
       case 1:
-        return _struct._ptr_data_item_1;
+        return _struct._exp_workaround_ptr_data_item_1;
       default:
         throw Exception('Invalid Array Helper generated.');
     }
@@ -303,10 +289,10 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        _struct._ptr_data_item_0 = value;
+        _struct._exp_workaround_ptr_data_item_0 = value;
         break;
       case 1:
-        _struct._ptr_data_item_1 = value;
+        _struct._exp_workaround_ptr_data_item_1 = value;
         break;
       default:
         throw Exception('Invalid Array Helper generated.');
@@ -348,13 +334,6 @@
   int numProtocols;
 }
 
-typedef CXInclusionVisitor = ffi.Void Function(
-  ffi.Pointer<ffi.Void>,
-  ffi.Pointer<CXSourceLocation>,
-  ffi.Uint32,
-  ffi.Pointer<ffi.Void>,
-);
-
 /// Describes the availability of a given entity on a particular platform, e.g.,
 /// a particular class might only be available on Mac OS 10.7 or newer.
 class CXPlatformAvailability extends ffi.Struct {}
@@ -365,8 +344,8 @@
 /// Use clang_getExpansionLocation() or clang_getSpellingLocation()
 /// to map a source location to a particular file, line, and column.
 class CXSourceLocation extends ffi.Struct {
-  ffi.Pointer<ffi.Void> _ptr_data_item_0;
-  ffi.Pointer<ffi.Void> _ptr_data_item_1;
+  ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_0;
+  ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_1;
 
   /// Helper for array `ptr_data`.
   ArrayHelper_CXSourceLocation_ptr_data_level0 get ptr_data =>
@@ -395,9 +374,9 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        return _struct._ptr_data_item_0;
+        return _struct._exp_workaround_ptr_data_item_0;
       case 1:
-        return _struct._ptr_data_item_1;
+        return _struct._exp_workaround_ptr_data_item_1;
       default:
         throw Exception('Invalid Array Helper generated.');
     }
@@ -407,10 +386,10 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        _struct._ptr_data_item_0 = value;
+        _struct._exp_workaround_ptr_data_item_0 = value;
         break;
       case 1:
-        _struct._ptr_data_item_1 = value;
+        _struct._exp_workaround_ptr_data_item_1 = value;
         break;
       default:
         throw Exception('Invalid Array Helper generated.');
@@ -423,8 +402,8 @@
 /// Use clang_getRangeStart() and clang_getRangeEnd() to retrieve the
 /// starting and end locations from a source range, respectively.
 class CXSourceRange extends ffi.Struct {
-  ffi.Pointer<ffi.Void> _ptr_data_item_0;
-  ffi.Pointer<ffi.Void> _ptr_data_item_1;
+  ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_0;
+  ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_1;
 
   /// Helper for array `ptr_data`.
   ArrayHelper_CXSourceRange_ptr_data_level0 get ptr_data =>
@@ -456,9 +435,9 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        return _struct._ptr_data_item_0;
+        return _struct._exp_workaround_ptr_data_item_0;
       case 1:
-        return _struct._ptr_data_item_1;
+        return _struct._exp_workaround_ptr_data_item_1;
       default:
         throw Exception('Invalid Array Helper generated.');
     }
@@ -468,10 +447,10 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        _struct._ptr_data_item_0 = value;
+        _struct._exp_workaround_ptr_data_item_0 = value;
         break;
       case 1:
-        _struct._ptr_data_item_1 = value;
+        _struct._exp_workaround_ptr_data_item_1 = value;
         break;
       default:
         throw Exception('Invalid Array Helper generated.');
@@ -532,13 +511,13 @@
 /// Describes a single preprocessing token.
 class CXToken extends ffi.Struct {
   @ffi.Uint32()
-  int _int_data_item_0;
+  int _exp_workaround_int_data_item_0;
   @ffi.Uint32()
-  int _int_data_item_1;
+  int _exp_workaround_int_data_item_1;
   @ffi.Uint32()
-  int _int_data_item_2;
+  int _exp_workaround_int_data_item_2;
   @ffi.Uint32()
-  int _int_data_item_3;
+  int _exp_workaround_int_data_item_3;
 
   /// Helper for array `int_data`.
   ArrayHelper_CXToken_int_data_level0 get int_data =>
@@ -566,13 +545,13 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        return _struct._int_data_item_0;
+        return _struct._exp_workaround_int_data_item_0;
       case 1:
-        return _struct._int_data_item_1;
+        return _struct._exp_workaround_int_data_item_1;
       case 2:
-        return _struct._int_data_item_2;
+        return _struct._exp_workaround_int_data_item_2;
       case 3:
-        return _struct._int_data_item_3;
+        return _struct._exp_workaround_int_data_item_3;
       default:
         throw Exception('Invalid Array Helper generated.');
     }
@@ -582,16 +561,16 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        _struct._int_data_item_0 = value;
+        _struct._exp_workaround_int_data_item_0 = value;
         break;
       case 1:
-        _struct._int_data_item_1 = value;
+        _struct._exp_workaround_int_data_item_1 = value;
         break;
       case 2:
-        _struct._int_data_item_2 = value;
+        _struct._exp_workaround_int_data_item_2 = value;
         break;
       case 3:
-        _struct._int_data_item_3 = value;
+        _struct._exp_workaround_int_data_item_3 = value;
         break;
       default:
         throw Exception('Invalid Array Helper generated.');
@@ -606,8 +585,8 @@
   @ffi.Int32()
   int kind;
 
-  ffi.Pointer<ffi.Void> _data_item_0;
-  ffi.Pointer<ffi.Void> _data_item_1;
+  ffi.Pointer<ffi.Void> _exp_workaround_data_item_0;
+  ffi.Pointer<ffi.Void> _exp_workaround_data_item_1;
 
   /// Helper for array `data`.
   ArrayHelper_CXType_data_level0 get data =>
@@ -634,9 +613,9 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        return _struct._data_item_0;
+        return _struct._exp_workaround_data_item_0;
       case 1:
-        return _struct._data_item_1;
+        return _struct._exp_workaround_data_item_1;
       default:
         throw Exception('Invalid Array Helper generated.');
     }
@@ -646,10 +625,10 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        _struct._data_item_0 = value;
+        _struct._exp_workaround_data_item_0 = value;
         break;
       case 1:
-        _struct._data_item_1 = value;
+        _struct._exp_workaround_data_item_1 = value;
         break;
       default:
         throw Exception('Invalid Array Helper generated.');
@@ -828,18 +807,60 @@
 
 /// A group of callbacks used by #clang_indexSourceFile and
 /// #clang_indexTranslationUnit.
+typedef _typedefC_3 = ffi.Int32 Function(
+  ffi.Pointer<ffi.Void>,
+  ffi.Pointer<ffi.Void>,
+);
+
+typedef _typedefC_4 = ffi.Void Function(
+  ffi.Pointer<ffi.Void>,
+  ffi.Pointer<ffi.Void>,
+  ffi.Pointer<ffi.Void>,
+);
+
+typedef _typedefC_5 = ffi.Pointer<ffi.Void> Function(
+  ffi.Pointer<ffi.Void>,
+  ffi.Pointer<ffi.Void>,
+  ffi.Pointer<ffi.Void>,
+);
+
+typedef _typedefC_6 = ffi.Pointer<ffi.Void> Function(
+  ffi.Pointer<ffi.Void>,
+  ffi.Pointer<CXIdxIncludedFileInfo>,
+);
+
+typedef _typedefC_7 = ffi.Pointer<ffi.Void> Function(
+  ffi.Pointer<ffi.Void>,
+  ffi.Pointer<CXIdxImportedASTFileInfo>,
+);
+
+typedef _typedefC_8 = ffi.Pointer<ffi.Void> Function(
+  ffi.Pointer<ffi.Void>,
+  ffi.Pointer<ffi.Void>,
+);
+
+typedef _typedefC_9 = ffi.Void Function(
+  ffi.Pointer<ffi.Void>,
+  ffi.Pointer<CXIdxDeclInfo>,
+);
+
+typedef _typedefC_10 = ffi.Void Function(
+  ffi.Pointer<ffi.Void>,
+  ffi.Pointer<CXIdxEntityRefInfo>,
+);
+
 class IndexerCallbacks extends ffi.Struct {
   /// Called periodically to check whether indexing should be aborted.
   /// Should return 0 to continue, and non-zero to abort.
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_3>> abortQuery;
+  ffi.Pointer<ffi.NativeFunction<_typedefC_3>> abortQuery;
 
   /// Called at the end of indexing; passes the complete diagnostic set.
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_4>> diagnostic;
+  ffi.Pointer<ffi.NativeFunction<_typedefC_4>> diagnostic;
 
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_5>> enteredMainFile;
+  ffi.Pointer<ffi.NativeFunction<_typedefC_5>> enteredMainFile;
 
   /// Called when a file gets \#included/\#imported.
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_6>> ppIncludedFile;
+  ffi.Pointer<ffi.NativeFunction<_typedefC_6>> ppIncludedFile;
 
   /// Called when a AST file (PCH or module) gets imported.
   ///
@@ -847,75 +868,17 @@
   /// the entities in an AST file). The recommended action is that, if the AST
   /// file is not already indexed, to initiate a new indexing job specific to
   /// the AST file.
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_7>> importedASTFile;
+  ffi.Pointer<ffi.NativeFunction<_typedefC_7>> importedASTFile;
 
   /// Called at the beginning of indexing a translation unit.
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_8>> startedTranslationUnit;
+  ffi.Pointer<ffi.NativeFunction<_typedefC_8>> startedTranslationUnit;
 
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_9>> indexDeclaration;
+  ffi.Pointer<ffi.NativeFunction<_typedefC_9>> indexDeclaration;
 
   /// Called to index a reference of an entity.
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_10>> indexEntityReference;
+  ffi.Pointer<ffi.NativeFunction<_typedefC_10>> indexEntityReference;
 }
 
-typedef ModifiedCXCursorVisitor = ffi.Int32 Function(
-  ffi.Pointer<CXCursor>,
-  ffi.Pointer<CXCursor>,
-  ffi.Pointer<ffi.Void>,
-);
-
-typedef _typedefC_noname_1 = ffi.Void Function(
-  ffi.Pointer<ffi.Void>,
-);
-
-typedef _typedefC_noname_10 = ffi.Void Function(
-  ffi.Pointer<ffi.Void>,
-  ffi.Pointer<CXIdxEntityRefInfo>,
-);
-
-typedef _typedefC_noname_2 = ffi.Int32 Function(
-  ffi.Pointer<ffi.Void>,
-  CXCursor,
-  CXSourceRange,
-);
-
-typedef _typedefC_noname_3 = ffi.Int32 Function(
-  ffi.Pointer<ffi.Void>,
-  ffi.Pointer<ffi.Void>,
-);
-
-typedef _typedefC_noname_4 = ffi.Void Function(
-  ffi.Pointer<ffi.Void>,
-  ffi.Pointer<ffi.Void>,
-  ffi.Pointer<ffi.Void>,
-);
-
-typedef _typedefC_noname_5 = ffi.Pointer<ffi.Void> Function(
-  ffi.Pointer<ffi.Void>,
-  ffi.Pointer<ffi.Void>,
-  ffi.Pointer<ffi.Void>,
-);
-
-typedef _typedefC_noname_6 = ffi.Pointer<ffi.Void> Function(
-  ffi.Pointer<ffi.Void>,
-  ffi.Pointer<CXIdxIncludedFileInfo>,
-);
-
-typedef _typedefC_noname_7 = ffi.Pointer<ffi.Void> Function(
-  ffi.Pointer<ffi.Void>,
-  ffi.Pointer<CXIdxImportedASTFileInfo>,
-);
-
-typedef _typedefC_noname_8 = ffi.Pointer<ffi.Void> Function(
-  ffi.Pointer<ffi.Void>,
-  ffi.Pointer<ffi.Void>,
-);
-
-typedef _typedefC_noname_9 = ffi.Void Function(
-  ffi.Pointer<ffi.Void>,
-  ffi.Pointer<CXIdxDeclInfo>,
-);
-
 /// Gets the general options associated with a CXIndex.
 ///
 /// \returns A bitmask of options, a bitwise OR of CXGlobalOpt_XXX flags that
@@ -2582,8 +2545,12 @@
   ffi.Pointer<CXSourceRange> c2,
 );
 
+typedef _typedefC_1 = ffi.Void Function(
+  ffi.Pointer<ffi.Void>,
+);
+
 void clang_executeOnThread(
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_1>> fn,
+  ffi.Pointer<ffi.NativeFunction<_typedefC_1>> fn,
   ffi.Pointer<ffi.Void> user_data,
   int stack_size,
 ) {
@@ -2599,13 +2566,13 @@
         'clang_executeOnThread');
 
 typedef _c_clang_executeOnThread = ffi.Void Function(
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_1>> fn,
+  ffi.Pointer<ffi.NativeFunction<_typedefC_1>> fn,
   ffi.Pointer<ffi.Void> user_data,
   ffi.Uint32 stack_size,
 );
 
 typedef _dart_clang_executeOnThread = void Function(
-  ffi.Pointer<ffi.NativeFunction<_typedefC_noname_1>> fn,
+  ffi.Pointer<ffi.NativeFunction<_typedefC_1>> fn,
   ffi.Pointer<ffi.Void> user_data,
   int stack_size,
 );
@@ -3438,13 +3405,20 @@
   ffi.Pointer<CXFileUniqueID> outID,
 );
 
+typedef CXInclusionVisitor_1 = ffi.Void Function(
+  ffi.Pointer<ffi.Void>,
+  ffi.Pointer<CXSourceLocation>,
+  ffi.Uint32,
+  ffi.Pointer<ffi.Void>,
+);
+
 /// Visit the set of preprocessor inclusions in a translation unit.
 /// The visitor function is called with the provided data for every included
 /// file.  This does not include headers included by the PCH file (unless one
 /// is inspecting the inclusions in the PCH file itself).
 void clang_getInclusions(
   ffi.Pointer<CXTranslationUnitImpl> tu,
-  ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor>> visitor,
+  ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor_1>> visitor,
   ffi.Pointer<ffi.Void> client_data,
 ) {
   return _clang_getInclusions(
@@ -3460,13 +3434,13 @@
 
 typedef _c_clang_getInclusions = ffi.Void Function(
   ffi.Pointer<CXTranslationUnitImpl> tu,
-  ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor>> visitor,
+  ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor_1>> visitor,
   ffi.Pointer<ffi.Void> client_data,
 );
 
 typedef _dart_clang_getInclusions = void Function(
   ffi.Pointer<CXTranslationUnitImpl> tu,
-  ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor>> visitor,
+  ffi.Pointer<ffi.NativeFunction<CXInclusionVisitor_1>> visitor,
   ffi.Pointer<ffi.Void> client_data,
 );
 
@@ -5112,11 +5086,17 @@
   int isEnabled,
 );
 
+typedef ModifiedCXCursorVisitor_1 = ffi.Int32 Function(
+  ffi.Pointer<CXCursor>,
+  ffi.Pointer<CXCursor>,
+  ffi.Pointer<ffi.Void>,
+);
+
 /// Visitor is a function pointer with parameters having pointers to cxcursor
 /// instead of cxcursor by default.
 int clang_visitChildren_wrap(
   ffi.Pointer<CXCursor> parent,
-  ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
+  ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
   ffi.Pointer<ffi.Void> clientData,
 ) {
   return _clang_visitChildren_wrap(
@@ -5132,12 +5112,12 @@
 
 typedef _c_clang_visitChildren_wrap = ffi.Uint32 Function(
   ffi.Pointer<CXCursor> parent,
-  ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
+  ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
   ffi.Pointer<ffi.Void> clientData,
 );
 
 typedef _dart_clang_visitChildren_wrap = int Function(
   ffi.Pointer<CXCursor> parent,
-  ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
+  ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
   ffi.Pointer<ffi.Void> clientData,
 );
diff --git a/example/libclang-example/pubspec.yaml b/example/libclang-example/pubspec.yaml
index 832f111..c29adb8 100644
--- a/example/libclang-example/pubspec.yaml
+++ b/example/libclang-example/pubspec.yaml
@@ -59,8 +59,17 @@
     unsigned long long: 8
     enum: 4
 
+  # Default is 'init'
+  init-function-name: init
+
   # False by default.
   array-workaround: true
 
+  # The header of the file, this is pasted as it is.
+  preamble: |
+    /// AUTO GENERATED FILE, DO NOT EDIT.
+    ///
+    /// Generated by `package:ffigen`.
+
   # Doc Comments for generated binings: Can be full, brief(default) or none.
   comments: full
diff --git a/example/simple/generated_bindings.dart b/example/simple/generated_bindings.dart
index 6e3a97b..54409b1 100644
--- a/example/simple/generated_bindings.dart
+++ b/example/simple/generated_bindings.dart
@@ -7,8 +7,8 @@
 ffi.DynamicLibrary _dylib;
 
 /// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib) {
-  _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary) {
+  _dylib = dynamicLibrary;
 }
 
 /// Adds 2 integers.
diff --git a/lib/src/code_generator.dart b/lib/src/code_generator.dart
index 9eb01b6..9af6dbe 100644
--- a/lib/src/code_generator.dart
+++ b/lib/src/code_generator.dart
@@ -13,5 +13,5 @@
 export 'code_generator/library.dart';
 export 'code_generator/struc.dart';
 export 'code_generator/type.dart';
-export 'code_generator/typedef.dart';
+export 'code_generator/typedefc.dart';
 
diff --git a/lib/src/code_generator/binding.dart b/lib/src/code_generator/binding.dart
index 127c0d2..f37c72c 100644
--- a/lib/src/code_generator/binding.dart
+++ b/lib/src/code_generator/binding.dart
@@ -9,11 +9,11 @@
 
 /// Base class for all Bindings.
 abstract class Binding {
-  final String name;
+  String name;
 
   final String dartDoc;
 
-  const Binding({@required this.name, this.dartDoc});
+  Binding({@required this.name, this.dartDoc});
 
   /// Converts a Binding to its actual string representation.
   BindingString toBindingString(Writer w);
diff --git a/lib/src/code_generator/constant.dart b/lib/src/code_generator/constant.dart
index bef22d8..dd5c657 100644
--- a/lib/src/code_generator/constant.dart
+++ b/lib/src/code_generator/constant.dart
@@ -28,7 +28,7 @@
   /// Put quotes if type is a string.
   final String rawValue;
 
-  const Constant({
+  Constant({
     @required String name,
     String dartDoc,
     @required this.type,
@@ -38,6 +38,7 @@
   @override
   BindingString toBindingString(Writer w) {
     final s = StringBuffer();
+    final constantName = name;
 
     if (dartDoc != null) {
       s.write('/// ');
@@ -45,7 +46,7 @@
       s.write('\n');
     }
 
-    s.write('const ${type.getDartType(w)} $name = $rawValue;\n\n');
+    s.write('const ${type.getDartType(w)} $constantName = $rawValue;\n\n');
 
     return BindingString(
         type: BindingStringType.constant, string: s.toString());
diff --git a/lib/src/code_generator/enum_class.dart b/lib/src/code_generator/enum_class.dart
index 90faf5b..1baea18 100644
--- a/lib/src/code_generator/enum_class.dart
+++ b/lib/src/code_generator/enum_class.dart
@@ -6,6 +6,7 @@
 
 import 'binding.dart';
 import 'binding_string.dart';
+import 'utils.dart';
 import 'writer.dart';
 
 /// A binding for enums in C.
@@ -35,6 +36,7 @@
   @override
   BindingString toBindingString(Writer w) {
     final s = StringBuffer();
+    final enclosingClassName = name;
 
     if (dartDoc != null) {
       s.write('/// ');
@@ -42,16 +44,22 @@
       s.write('\n');
     }
 
+    /// Adding [enclosingClassName] because dart doesn't allow class member
+    /// to have the same name as the class.
+    final localUniqueNamer = UniqueNamer({enclosingClassName});
+
     // Print enclosing class.
-    s.write('class $name {\n');
+    s.write('class $enclosingClassName {\n');
     const depth = '  ';
     for (final ec in enumConstants) {
+      final enum_value_name =
+          localUniqueNamer.makeUnique(ec.name);
       if (ec.dartDoc != null) {
         s.write(depth + '/// ');
         s.writeAll(ec.dartDoc.split('\n'), '\n' + depth + '/// ');
         s.write('\n');
       }
-      s.write(depth + 'static const int ${ec.name} = ${ec.value};\n');
+      s.write(depth + 'static const int ${enum_value_name} = ${ec.value};\n');
     }
     s.write('}\n\n');
 
diff --git a/lib/src/code_generator/func.dart b/lib/src/code_generator/func.dart
index 688c573..ffc1509 100644
--- a/lib/src/code_generator/func.dart
+++ b/lib/src/code_generator/func.dart
@@ -28,15 +28,19 @@
 /// typedef _dart_sum = int Function(int a, int b);
 /// ```
 class Func extends Binding {
+  final String lookupSymbolName;
   final Type returnType;
   final List<Parameter> parameters;
 
+  /// [lookupSymbolName], if not provided, takes the value of [name].
   Func({
     @required String name,
+    String lookupSymbolName,
     String dartDoc,
     @required this.returnType,
     List<Parameter> parameters,
   })  : parameters = parameters ?? [],
+        lookupSymbolName = lookupSymbolName ?? name,
         super(name: name, dartDoc: dartDoc) {
     for (var i = 0; i < this.parameters.length; i++) {
       if (this.parameters[i].name == null ||
@@ -49,10 +53,22 @@
   @override
   BindingString toBindingString(Writer w) {
     final s = StringBuffer();
+    final enclosingFuncName = name;
 
-    final funcVarName = '_$name';
-    final typedefC = '_c_$name';
-    final typedefDart = '_dart_$name';
+    // Ensure name conflicts are resolved for typedefs generated.
+    final funcVarName = w.uniqueNamer.makeUnique('_$name');
+    final typedefC = w.uniqueNamer.makeUnique('_c_$name');
+    final typedefDart = w.uniqueNamer.makeUnique('_dart_$name');
+
+    // Write typedef's required by parameters and resolve name conflicts.
+    for (final p in parameters) {
+      final base = p.type.getBaseType();
+      if (base.broadType == BroadType.NativeFunction) {
+        base.nativeFunc.name =
+            w.uniqueNamer.makeUnique(base.nativeFunc.name);
+        s.write(base.nativeFunc.toTypedefString(w));
+      }
+    }
 
     if (dartDoc != null) {
       s.write('/// ');
@@ -61,7 +77,7 @@
     }
 
     // Write enclosing function.
-    s.write('${returnType.getDartType(w)} $name(\n');
+    s.write('${returnType.getDartType(w)} $enclosingFuncName(\n');
     for (final p in parameters) {
       s.write('  ${p.type.getDartType(w)} ${p.name},\n');
     }
@@ -75,7 +91,7 @@
 
     // Write function with dylib lookup.
     s.write(
-        "final $typedefDart $funcVarName = ${w.dylibIdentifier}.lookupFunction<$typedefC,$typedefDart>('$name');\n\n");
+        "final $typedefDart $funcVarName = ${w.dylibIdentifier}.lookupFunction<$typedefC,$typedefDart>('$lookupSymbolName');\n\n");
 
     // Write typdef for C.
     s.write('typedef $typedefC = ${returnType.getCType(w)} Function(\n');
diff --git a/lib/src/code_generator/global.dart b/lib/src/code_generator/global.dart
index 8729785..2e41d82 100644
--- a/lib/src/code_generator/global.dart
+++ b/lib/src/code_generator/global.dart
@@ -20,10 +20,12 @@
 /// final int a = _dylib.lookup<ffi.Int32>('a').value;
 /// ```
 class Global extends Binding {
+  final String lookupSymbolName;
   final Type type;
 
-  const Global({
+  Global({
     @required String name,
+    @required this.lookupSymbolName,
     @required this.type,
     String dartDoc,
   }) : super(name: name, dartDoc: dartDoc);
@@ -31,7 +33,7 @@
   @override
   BindingString toBindingString(Writer w) {
     final s = StringBuffer();
-
+    final globalVarName = name;
     if (dartDoc != null) {
       s.write('/// ');
       s.writeAll(dartDoc.split('\n'), '\n/// ');
@@ -39,7 +41,7 @@
     }
 
     s.write(
-        "final ${type.getDartType(w)} $name = ${w.dylibIdentifier}.lookup<${type.getCType(w)}>('$name').value;\n\n");
+        "final ${type.getDartType(w)} $globalVarName = ${w.dylibIdentifier}.lookup<${type.getCType(w)}>('$lookupSymbolName').value;\n\n");
 
     return BindingString(type: BindingStringType.global, string: s.toString());
   }
diff --git a/lib/src/code_generator/library.dart b/lib/src/code_generator/library.dart
index 8ae4a06..027c1f1 100644
--- a/lib/src/code_generator/library.dart
+++ b/lib/src/code_generator/library.dart
@@ -8,33 +8,46 @@
 import 'package:meta/meta.dart';
 
 import 'binding.dart';
+import 'utils.dart';
 import 'writer.dart';
 
-var _logger = Logger('code_generator');
+var _logger = Logger('code_generator:library.dart');
 
 /// Container for all Bindings.
 class Library {
-  /// Variable identifier used for dynamicLibrary. Defaults to `_dylib`,
-  final String dylibIdentifier;
-
-  /// Init function for providing dynamic library. Defaults to `init`,
-  ///
-  /// Can be renamed in case of name conflicts with something else.
-  final String initFunctionIdentifier;
-
-  /// Header of file.
-  final String header;
-
   /// List of bindings in this library.
   final List<Binding> bindings;
 
+  Writer _writer;
+  Writer get writer => _writer;
+
   Library({
     @required this.bindings,
-    this.dylibIdentifier = '_dylib',
-    this.initFunctionIdentifier = 'init',
-    this.header,
-  })  : assert(dylibIdentifier != null),
-        assert(initFunctionIdentifier != null);
+    String header,
+    String initFunctionIdentifier = 'init',
+  }) {
+    // Handle any declaration-declaration name conflict.
+    final declConflictHandler = UniqueNamer({});
+    for (final b in bindings) {
+      // Print warning if name was conflicting and has been changed.
+      if (declConflictHandler.isUsed(b.name)) {
+        final oldName = b.name;
+        b.name = declConflictHandler.makeUnique(b.name);
+
+        _logger.warning(
+            "Resolved name conflict: Declaration '$oldName' and has been renamed to '${b.name}'.");
+      } else {
+        declConflictHandler.markUsed(b.name);
+      }
+    }
+
+    final declarationNames = bindings.map((e) => e.name).toSet();
+    _writer = Writer(
+      usedUpNames: declarationNames,
+      initFunctionIdentifier: initFunctionIdentifier,
+      header: header,
+    );
+  }
 
   /// Sort all bindings in alphabetical order.
   void sort() {
@@ -53,7 +66,6 @@
 
   /// Generates bindings and stores it in given [Writer].
   void _generate(Writer w) {
-    w.header = header;
     for (final b in bindings) {
       w.addBindingString(b.toBindingString(w));
     }
@@ -70,10 +82,7 @@
 
   /// Generates the bindings.
   String generate() {
-    final w = Writer(
-      dylibIdentifier: dylibIdentifier,
-      initFunctionIdentifier: initFunctionIdentifier,
-    );
+    final w = writer;
     _generate(w);
     return w.generate();
   }
diff --git a/lib/src/code_generator/struc.dart b/lib/src/code_generator/struc.dart
index 5e2db56..949c239 100644
--- a/lib/src/code_generator/struc.dart
+++ b/lib/src/code_generator/struc.dart
@@ -7,6 +7,7 @@
 import 'binding.dart';
 import 'binding_string.dart';
 import 'type.dart';
+import 'utils.dart';
 import 'writer.dart';
 
 /// A binding for C Struct.
@@ -34,7 +35,7 @@
 /// }
 /// ```
 class Struc extends Binding {
-  final List<Member> members;
+  List<Member> members;
 
   Struc({
     @required String name,
@@ -55,8 +56,9 @@
 
   @override
   BindingString toBindingString(Writer w) {
+    members = members ?? [];
     final s = StringBuffer();
-
+    final enclosingClassName = name;
     if (dartDoc != null) {
       s.write('/// ');
       s.writeAll(dartDoc.split('\n'), '\n/// ');
@@ -65,18 +67,37 @@
 
     final helpers = <ArrayHelper>[];
 
-    // Write class declaration.
-    s.write('class $name extends ${w.ffiLibraryPrefix}.Struct{\n');
+    // Write typedef's required by members and resolve name conflicts.
     for (final m in members) {
+      final base = m.type.getBaseType();
+      if (base.broadType == BroadType.NativeFunction) {
+        base.nativeFunc.name =
+            w.uniqueNamer.makeUnique(base.nativeFunc.name);
+        s.write(base.nativeFunc.toTypedefString(w));
+      }
+    }
+
+    final expandedArrayItemPrefix = getUniqueExpandedArrayItemPrefix();
+
+    /// Adding [enclosingClassName] because dart doesn't allow class member
+    /// to have the same name as the class.
+    final localUniqueNamer = UniqueNamer({enclosingClassName});
+
+    // Write class declaration.
+    s.write(
+        'class $enclosingClassName extends ${w.ffiLibraryPrefix}.Struct{\n');
+    for (final m in members) {
+      final memberName = localUniqueNamer.makeUnique(m.name);
       if (m.type.broadType == BroadType.ConstantArray) {
         // TODO(5): Remove array helpers when inline array support arives.
         final arrayHelper = ArrayHelper(
-          helperClassGroupName: 'ArrayHelper_${name}_${m.name}',
+          helperClassGroupName:
+              '${w.arrayHelperClassPrefix}_${enclosingClassName}_${memberName}',
           elementType: m.type.getBaseArrayType(),
           dimensions: _getArrayDimensionLengths(m.type),
-          name: m.name,
-          structName: name,
-          elementNamePrefix: '_${m.name}_item_',
+          name: memberName,
+          structName: enclosingClassName,
+          elementNamePrefix: '${expandedArrayItemPrefix}${memberName}_item_',
         );
         s.write(arrayHelper.declarationString(w));
         helpers.add(arrayHelper);
@@ -90,7 +111,7 @@
         if (m.type.isPrimitive) {
           s.write('$depth@${m.type.getCType(w)}()\n');
         }
-        s.write('$depth${m.type.getDartType(w)} ${m.name};\n\n');
+        s.write('$depth${m.type.getDartType(w)} ${memberName};\n\n');
       }
     }
     s.write('}\n\n');
@@ -101,6 +122,22 @@
 
     return BindingString(type: BindingStringType.struc, string: s.toString());
   }
+
+  /// Gets a unique prefix in local namespace for expanded array items.
+  String getUniqueExpandedArrayItemPrefix() {
+    final base = '_unique';
+    String expandedArrayItemPrefix = base;
+    int suffixInt = 0;
+    for (int i = 0; i < members.length; i++) {
+      if (members[i].name.startsWith(expandedArrayItemPrefix)) {
+        // Not a unique prefix, start over with a new suffix.
+        i = -1;
+        suffixInt++;
+        expandedArrayItemPrefix = '${base}${suffixInt}';
+      }
+    }
+    return expandedArrayItemPrefix + '_';
+  }
 }
 
 class Member {
diff --git a/lib/src/code_generator/type.dart b/lib/src/code_generator/type.dart
index dccdec3..a07b776 100644
--- a/lib/src/code_generator/type.dart
+++ b/lib/src/code_generator/type.dart
@@ -4,6 +4,8 @@
 
 import 'package:meta/meta.dart';
 
+import 'struc.dart';
+import 'typedefc.dart';
 import 'writer.dart';
 
 class _SubType {
@@ -62,11 +64,11 @@
     SupportedNativeType.IntPtr: _SubType(c: 'IntPtr', dart: 'int'),
   };
 
-  /// For providing name of Struct.
-  String structName;
+  /// Reference to the [Struc] binding this type refers to.
+  Struc struc;
 
-  /// For providing name of nativeFunc.
-  String nativeFuncName;
+  /// Reference to the [TypedefC] this type refers to.
+  TypedefC nativeFunc;
 
   /// For providing [SupportedNativeType] only.
   final SupportedNativeType nativeType;
@@ -86,9 +88,9 @@
   Type._({
     @required this.broadType,
     this.child,
-    this.structName,
+    this.struc,
     this.nativeType,
-    this.nativeFuncName,
+    this.nativeFunc,
     this.length,
     this.unimplementedReason,
   });
@@ -96,12 +98,11 @@
   factory Type.pointer(Type child) {
     return Type._(broadType: BroadType.Pointer, child: child);
   }
-  factory Type.struct(String structName) {
-    return Type._(broadType: BroadType.Struct, structName: structName);
+  factory Type.struct(Struc struc) {
+    return Type._(broadType: BroadType.Struct, struc: struc);
   }
-  factory Type.nativeFunc(String nativeFuncName) {
-    return Type._(
-        broadType: BroadType.NativeFunction, nativeFuncName: nativeFuncName);
+  factory Type.nativeFunc(TypedefC nativeFunc) {
+    return Type._(broadType: BroadType.NativeFunction, nativeFunc: nativeFunc);
   }
   factory Type.nativeType(SupportedNativeType nativeType) {
     return Type._(broadType: BroadType.NativeType, nativeType: nativeType);
@@ -124,15 +125,15 @@
         broadType: BroadType.Unimplemented, unimplementedReason: reason);
   }
 
-  /// Get base broad type for any type.
+  /// Get base type for any type.
   ///
-  /// E.g int** has base Broadtype as NativeType,
-  /// double[2][3] has base broadtype as double.
-  BroadType getBaseBroadType() {
+  /// E.g int** has base [Type] with [Broadtype] as NativeType,
+  /// double[2][3] has base [Type] with [Broadtype] as double.
+  Type getBaseType() {
     if (child != null) {
-      return child.getBaseBroadType();
+      return child.getBaseType();
     } else {
-      return broadType;
+      return this;
     }
   }
 
@@ -157,9 +158,9 @@
       case BroadType.Pointer:
         return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
       case BroadType.Struct:
-        return structName;
+        return '${struc.name}';
       case BroadType.NativeFunction:
-        return '${w.ffiLibraryPrefix}.NativeFunction<${nativeFuncName}>';
+        return '${w.ffiLibraryPrefix}.NativeFunction<${nativeFunc.name}>';
       case BroadType
           .IncompleteArray: // Array parameters are treated as Pointers in C.
         return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
@@ -178,9 +179,9 @@
       case BroadType.Pointer:
         return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
       case BroadType.Struct:
-        return structName;
+        return '${struc.name}';
       case BroadType.NativeFunction:
-        return '${w.ffiLibraryPrefix}.NativeFunction<${nativeFuncName}>';
+        return '${w.ffiLibraryPrefix}.NativeFunction<${nativeFunc.name}>';
       case BroadType
           .IncompleteArray: // Array parameters are treated as Pointers in C.
         return '${w.ffiLibraryPrefix}.Pointer<${child.getCType(w)}>';
diff --git a/lib/src/code_generator/typedef.dart b/lib/src/code_generator/typedefc.dart
similarity index 71%
rename from lib/src/code_generator/typedef.dart
rename to lib/src/code_generator/typedefc.dart
index ea9568f..28075aa 100644
--- a/lib/src/code_generator/typedef.dart
+++ b/lib/src/code_generator/typedefc.dart
@@ -4,8 +4,6 @@
 
 import 'package:meta/meta.dart';
 
-import 'binding.dart';
-import 'binding_string.dart';
 import 'func.dart' show Parameter;
 import 'type.dart';
 import 'writer.dart';
@@ -18,23 +16,25 @@
 ///   $parameter2...,
 ///   .
 ///   .
-/// );`
+/// );
 /// ```
-/// Note: This doesn't bind with anything.
-class TypedefC extends Binding {
+/// Used for generating typedefs for `Pointer<NativeFunction>`.
+///
+/// Name conflict resolution must be done before using.
+class TypedefC {
+  String name;
+  String dartDoc;
   final Type returnType;
   final List<Parameter> parameters;
 
   TypedefC({
-    @required String name,
-    String dartDoc,
+    @required this.name,
+    this.dartDoc,
     @required this.returnType,
     List<Parameter> parameters,
-  })  : parameters = parameters ?? [],
-        super(name: name, dartDoc: dartDoc);
+  }) : parameters = parameters ?? [];
 
-  @override
-  BindingString toBindingString(Writer w) {
+  String toTypedefString(Writer w) {
     final s = StringBuffer();
 
     if (dartDoc != null) {
@@ -49,6 +49,6 @@
     }
     s.write(');\n\n');
 
-    return BindingString(type: BindingStringType.typeDef, string: s.toString());
+    return s.toString();
   }
 }
diff --git a/lib/src/code_generator/utils.dart b/lib/src/code_generator/utils.dart
new file mode 100644
index 0000000..fbb1cce
--- /dev/null
+++ b/lib/src/code_generator/utils.dart
@@ -0,0 +1,37 @@
+class UniqueNamer {
+  final Set<String> _usedUpNames;
+  UniqueNamer(this._usedUpNames);
+
+  /// Returns a unique name by appending `_<int>` to it if necessary.
+  ///
+  /// Adds the resulting name to the used names by default.
+  String makeUnique(String name, [bool addToUsedUpNames = true]) {
+    String cr_name = name;
+    int i = 1;
+    while (_usedUpNames.contains(cr_name)) {
+      cr_name = '${name}_$i';
+      i++;
+    }
+    if (addToUsedUpNames) {
+      _usedUpNames.add(cr_name);
+    }
+    return cr_name;
+  }
+
+  /// Adds a name to used names.
+  ///
+  /// Note: [makeUnique] also adds the name by default.
+  void markUsed(String name) {
+    _usedUpNames.add(name);
+  }
+
+  /// Returns true if a name has been used before.
+  bool isUsed(String name) {
+    return _usedUpNames.contains(name);
+  }
+
+  /// Returns true if a name has not been used before.
+  bool isUnique(String name) {
+    return !_usedUpNames.contains(name);
+  }
+}
diff --git a/lib/src/code_generator/writer.dart b/lib/src/code_generator/writer.dart
index cc4496f..aa8129c 100644
--- a/lib/src/code_generator/writer.dart
+++ b/lib/src/code_generator/writer.dart
@@ -2,29 +2,62 @@
 // 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/utils.dart';
+import 'package:meta/meta.dart';
+
 import 'binding_string.dart';
 
 /// To store generated String bindings.
 class Writer {
-  String header;
-  String dylibIdentifier;
-  String initFunctionIdentifier;
+  final String header;
+  String _initFunctionIdentifier;
 
-  /// dart:ffi library import prefix.
-  String ffiLibraryPrefix;
+  final UniqueNamer uniqueNamer;
+
+  String _ffiLibraryPrefix;
+  String get ffiLibraryPrefix =>
+      _ffiLibraryPrefix ??= uniqueNamer.makeUnique('ffi');
+
+  String _dylibIdentifier;
+  String get dylibIdentifier =>
+      _dylibIdentifier ??= uniqueNamer.makeUnique('_dylib');
+
+  String _arrayHelperClassPrefix;
+
+  /// Guaranteed to be a unique prefix.
+  String get arrayHelperClassPrefix => _arrayHelperClassPrefix;
 
   final List<BindingString> _bindings = [];
 
+  /// [usedUpNames] should contain names of all the declarations which are
+  /// already used. This is used to avoid name collisions.
   Writer({
-    this.dylibIdentifier = '_dylib',
-    this.initFunctionIdentifier = 'init',
-    this.ffiLibraryPrefix = 'ffi',
-  });
+    @required Set<String> usedUpNames,
+    String initFunctionIdentifier = 'init',
+    this.header,
+  })  : uniqueNamer = UniqueNamer(usedUpNames),
+        assert(initFunctionIdentifier != null) {
+    _initFunctionIdentifier =
+        uniqueNamer.makeUnique(initFunctionIdentifier);
 
+    /// Finding a unique prefix for Array Helper Classes and store into
+    /// [_arrayHelperClassPrefix].
+    final base = 'ArrayHelper';
+    _arrayHelperClassPrefix = base;
+    int suffixInt = 0;
+    for (int i = 0; i < usedUpNames.length; i++) {
+      if (usedUpNames.elementAt(i).startsWith(_arrayHelperClassPrefix)) {
+        // Not a unique prefix, start over with a new suffix.
+        i = -1;
+        suffixInt++;
+        _arrayHelperClassPrefix = '${base}${suffixInt}';
+      }
+    }
+  }
   String generate() {
     final s = StringBuffer();
 
-    // Write header (if any)
+    // Write file header (if any).
     if (header != null) {
       s.write(header);
       s.write('\n');
@@ -46,8 +79,8 @@
     s.write('\n');
     s.write('/// Initialises the Dynamic library.\n');
     s.write(
-        'void $initFunctionIdentifier($ffiLibraryPrefix.DynamicLibrary dylib){\n');
-    s.write('  ${dylibIdentifier} = dylib;\n');
+        'void $_initFunctionIdentifier($ffiLibraryPrefix.DynamicLibrary dynamicLibrary){\n');
+    s.write('  ${dylibIdentifier} = dynamicLibrary;\n');
     s.write('}\n');
 
     // Write bindings.
diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart
index fbd2ae6..7abfb66 100644
--- a/lib/src/config_provider/config.dart
+++ b/lib/src/config_provider/config.dart
@@ -15,10 +15,10 @@
 import 'package:yaml/yaml.dart';
 
 import '../strings.dart' as strings;
-import 'filter.dart';
+import 'declaration.dart';
 import 'spec_utils.dart';
 
-var _logger = Logger('config_provider/config');
+var _logger = Logger('config_provider:config.dart');
 
 /// Provides configurations to other modules.
 ///
@@ -44,14 +44,14 @@
   /// CommandLine Arguments to pass to clang_compiler.
   List<String> compilerOpts;
 
-  /// Filter for functions.
-  Filter functionFilters;
+  /// Declaration config for Functions.
+  Declaration functionDecl;
 
-  /// Filter for structs.
-  Filter structFilters;
+  /// Declaration config for Structs.
+  Declaration structDecl;
 
-  /// Filter for enumClass.
-  Filter enumClassFilters;
+  /// Declaration config for Enums.
+  Declaration enumClassDecl;
 
   /// If generated bindings should be sorted alphabetically.
   bool sort;
@@ -67,23 +67,11 @@
   /// If false(default), structs with inline array members will have all its members removed.
   bool arrayWorkaround;
 
-  /// Manually creating configurations.
-  ///
-  /// Use [Config.fromYaml] if extracting info from a yaml file.
-  /// Ensure that log printing is setup before using this.
-  Config.raw({
-    this.output,
-    @required this.libclang_dylib_path,
-    @required this.headers,
-    this.headerFilter,
-    this.compilerOpts,
-    this.functionFilters,
-    this.structFilters,
-    this.enumClassFilters,
-    this.sort = false,
-    this.useSupportedTypedefs = true,
-    this.comment,
-  });
+  /// Name of the init function used to initialise the dynamic library.
+  String initFunctionName;
+
+  /// Header of the generated bindings.
+  String preamble;
 
   Config._();
 
@@ -137,7 +125,7 @@
       if (map.containsKey(key)) {
         spec.extractedResult(spec.extractor(map[key]));
       } else {
-        spec.extractedResult(spec.defaultValue);
+        spec.extractedResult(spec.defaultValue?.call());
       }
     }
   }
@@ -152,14 +140,13 @@
         isRequired: true,
         validator: outputValidator,
         extractor: outputExtractor,
-        defaultValue: null,
         extractedResult: (dynamic result) => output = result as String,
       ),
       strings.libclang_dylib_folder: Specification<String>(
         description:
             'Path to folder containing libclang dynamic library, used to parse C headers',
         isRequired: false,
-        defaultValue: getDylibPath(Platform.script
+        defaultValue: () => getDylibPath(Platform.script
             .resolve(path.join('..', 'tool', 'wrapped_libclang'))
             .toFilePath()),
         validator: libclangDylibValidator,
@@ -178,7 +165,7 @@
         description: 'Include/Exclude inclusion headers',
         validator: headerFilterValidator,
         extractor: headerFilterExtractor,
-        defaultValue: HeaderFilter(),
+        defaultValue: () => HeaderFilter(),
         extractedResult: (dynamic result) {
           return headerFilter = result as HeaderFilter;
         },
@@ -188,40 +175,47 @@
         isRequired: false,
         validator: compilerOptsValidator,
         extractor: compilerOptsExtractor,
-        defaultValue: null,
         extractedResult: (dynamic result) =>
             compilerOpts = result as List<String>,
       ),
-      strings.functions: Specification<Filter>(
+      strings.functions: Specification<Declaration>(
         description: 'Filter for functions',
         isRequired: false,
-        validator: filterValidator,
-        extractor: filterExtractor,
-        defaultValue: null,
-        extractedResult: (dynamic result) => functionFilters = result as Filter,
+        validator: declarationConfigValidator,
+        extractor: declarationConfigExtractor,
+        defaultValue: () => Declaration(declarationTypeName: 'Function'),
+        extractedResult: (dynamic result) {
+          functionDecl = result as Declaration;
+          functionDecl.declarationTypeName = 'Function';
+        },
       ),
-      strings.structs: Specification<Filter>(
+      strings.structs: Specification<Declaration>(
         description: 'Filter for Structs',
         isRequired: false,
-        validator: filterValidator,
-        extractor: filterExtractor,
-        defaultValue: null,
-        extractedResult: (dynamic result) => structFilters = result as Filter,
+        validator: declarationConfigValidator,
+        extractor: declarationConfigExtractor,
+        defaultValue: () => Declaration(declarationTypeName: 'Struct'),
+        extractedResult: (dynamic result) {
+          structDecl = result as Declaration;
+          structDecl.declarationTypeName = 'Struct';
+        },
       ),
-      strings.enums: Specification<Filter>(
+      strings.enums: Specification<Declaration>(
         description: 'Filter for enums',
         isRequired: false,
-        validator: filterValidator,
-        extractor: filterExtractor,
-        defaultValue: null,
-        extractedResult: (dynamic result) =>
-            enumClassFilters = result as Filter,
+        validator: declarationConfigValidator,
+        extractor: declarationConfigExtractor,
+        defaultValue: () => Declaration(declarationTypeName: 'Enum'),
+        extractedResult: (dynamic result) {
+          enumClassDecl = result as Declaration;
+          enumClassDecl.declarationTypeName = 'Enum';
+        },
       ),
       strings.sizemap: Specification<Map<int, SupportedNativeType>>(
         description: 'map of types: byte size in int',
         validator: sizemapValidator,
         extractor: sizemapExtractor,
-        defaultValue: <int, SupportedNativeType>{},
+        defaultValue: () => <int, SupportedNativeType>{},
         extractedResult: (dynamic result) {
           final map = result as Map<int, SupportedNativeType>;
           for (final key in map.keys) {
@@ -236,7 +230,7 @@
         isRequired: false,
         validator: booleanValidator,
         extractor: booleanExtractor,
-        defaultValue: false,
+        defaultValue: () => false,
         extractedResult: (dynamic result) => sort = result as bool,
       ),
       strings.useSupportedTypedefs: Specification<bool>(
@@ -244,7 +238,7 @@
         isRequired: false,
         validator: booleanValidator,
         extractor: booleanExtractor,
-        defaultValue: true,
+        defaultValue: () => true,
         extractedResult: (dynamic result) =>
             useSupportedTypedefs = result as bool,
       ),
@@ -253,7 +247,7 @@
         isRequired: false,
         validator: commentValidator,
         extractor: commentExtractor,
-        defaultValue: strings.brief,
+        defaultValue: () => strings.brief,
         extractedResult: (dynamic result) => comment = result as String,
       ),
       strings.arrayWorkaround: Specification<bool>(
@@ -262,9 +256,25 @@
         isRequired: false,
         validator: booleanValidator,
         extractor: booleanExtractor,
-        defaultValue: false,
+        defaultValue: () => false,
         extractedResult: (dynamic result) => arrayWorkaround = result as bool,
       ),
+      strings.initFunctionName: Specification<String>(
+        description: 'Name of the init function to use',
+        isRequired: false,
+        validator: nonEmptyStringValidator,
+        extractor: stringExtractor,
+        defaultValue: () => 'init',
+        extractedResult: (dynamic result) =>
+            initFunctionName = result as String,
+      ),
+      strings.preamble: Specification<String>(
+        description: 'Header String for the generated bindings',
+        isRequired: false,
+        validator: nonEmptyStringValidator,
+        extractor: stringExtractor,
+        extractedResult: (dynamic result) => preamble = result as String,
+      ),
     };
   }
 }
@@ -276,7 +286,8 @@
   final String description;
   final bool Function(String name, dynamic value) validator;
   final E Function(dynamic map) extractor;
-  final E defaultValue;
+  final E Function() defaultValue;
+
   final bool isRequired;
   final void Function(dynamic result) extractedResult;
 
diff --git a/lib/src/config_provider/declaration.dart b/lib/src/config_provider/declaration.dart
new file mode 100644
index 0000000..4674bc5
--- /dev/null
+++ b/lib/src/config_provider/declaration.dart
@@ -0,0 +1,107 @@
+// 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 'package:logging/logging.dart';
+
+var _logger = Logger('config_provider:declaration.dart');
+
+/// A generic declaration config.
+class Declaration {
+  /// Display name of a declaration type.
+  ///
+  /// Used for logging and warning purposes.
+  String declarationTypeName;
+
+  // matchers
+  List<RegExp> _includeMatchers = [];
+  Set<String> _includeFull = {};
+  List<RegExp> _excludeMatchers = [];
+  Set<String> _excludeFull = {};
+  String _globalPrefix = '';
+  Map<String, String> _prefixReplacement = {};
+
+  Declaration({
+    this.declarationTypeName = 'declaration',
+    List<String> includeMatchers,
+    List<String> includeFull,
+    List<String> excludeMatchers,
+    List<String> excludeFull,
+    String globalPrefix,
+    Map<String, String> prefixReplacement,
+  }) {
+    if (includeMatchers != null) {
+      _includeMatchers =
+          includeMatchers.map((e) => RegExp(e, dotAll: true)).toList();
+    }
+    if (includeFull != null) {
+      _includeFull = includeFull.map((e) => e).toSet();
+    }
+    if (excludeMatchers != null) {
+      _excludeMatchers =
+          excludeMatchers.map((e) => RegExp(e, dotAll: true)).toList();
+    }
+    if (excludeFull != null) {
+      _excludeFull = excludeFull.map((e) => e).toSet();
+    }
+    if (globalPrefix != null) {
+      _globalPrefix = globalPrefix;
+    }
+    if (prefixReplacement != null) {
+      _prefixReplacement = prefixReplacement;
+    }
+  }
+
+  /// Applies prefix and replacement and returns the result.
+  ///
+  /// Also logs warnings if declaration starts with '_'.
+  String getPrefixedName(String name) {
+    // Apply prefix replacement.
+    for (final pattern in _prefixReplacement.keys) {
+      if (name.startsWith(pattern)) {
+        name = name.replaceFirst(pattern, _prefixReplacement[pattern]);
+        break;
+      }
+    }
+
+    // Apply global prefixes.
+    name = '${_globalPrefix}$name';
+
+    // Warn user if a declaration starts with '_'.
+    if (name.startsWith('_')) {
+      _logger.warning(
+          "Generated $declarationTypeName '$name' start's with '_' and therefore will be private.");
+    }
+    return name;
+  }
+
+  /// Checks if a name is allowed by a filter.
+  bool shouldInclude(String name) {
+    if (_excludeFull.contains(name)) {
+      return false;
+    }
+
+    for (final em in _excludeMatchers) {
+      if (em.firstMatch(name)?.end == name.length) {
+        return false;
+      }
+    }
+
+    if (_includeFull.contains(name)) {
+      return true;
+    }
+
+    for (final im in _includeMatchers) {
+      if (im.firstMatch(name)?.end == name.length) {
+        return true;
+      }
+    }
+
+    // If user has provided 'include' field in the filter, then default
+    // matching is false.
+    if (_includeMatchers.isNotEmpty || _includeFull.isNotEmpty) {
+      return false;
+    } else {
+      return true;
+    }
+  }
+}
diff --git a/lib/src/config_provider/filter.dart b/lib/src/config_provider/filter.dart
deleted file mode 100644
index b35dc0b..0000000
--- a/lib/src/config_provider/filter.dart
+++ /dev/null
@@ -1,80 +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.
-
-/// A generic filter for filtering strings based on regexes and prefixes.
-///
-/// Excludes override includes.
-///
-/// User can provide fiters for functions, structs, enums and include/exclude
-/// them using regexp and full name matching.
-class Filter {
-  // matchers
-  List<RegExp> _includeMatchers = [];
-  Set<String> _includeFull = {};
-  List<RegExp> _excludeMatchers = [];
-  Set<String> _excludeFull = {};
-
-  Filter({
-    List<String> includeMatchers,
-    List<String> includeFull,
-    List<String> excludeMatchers,
-    List<String> excludeFull,
-  }) {
-    if (includeMatchers != null) {
-      _includeMatchers =
-          includeMatchers.map((e) => RegExp(e, dotAll: true)).toList();
-    }
-    if (includeFull != null) {
-      _includeFull = includeFull.map((e) => e).toSet();
-    }
-    if (excludeMatchers != null) {
-      _excludeMatchers =
-          excludeMatchers.map((e) => RegExp(e, dotAll: true)).toList();
-    }
-    if (excludeFull != null) {
-      _excludeFull = excludeFull.map((e) => e).toSet();
-    }
-  }
-
-  /// Checks if a name is allowed by a filter.
-  bool shouldInclude(String name) {
-    if (_excludeFull.contains(name)) {
-      return false;
-    }
-
-    for (final em in _excludeMatchers) {
-      if (em.firstMatch(name)?.end == name.length) {
-        return false;
-      }
-    }
-
-    if (_includeFull.contains(name)) {
-      return true;
-    }
-
-    for (final im in _includeMatchers) {
-      if (im.firstMatch(name)?.end == name.length) {
-        return true;
-      }
-    }
-
-    // If user has provided 'include' field in the filter, then default
-    // matching is false.
-    if (_includeMatchers.isNotEmpty || _includeFull.isNotEmpty) {
-      return false;
-    } else {
-      return true;
-    }
-  }
-
-  @override
-  String toString() {
-    return ''' (includeFull, includeMatchers, excludeFull, excludeMatchers)
-$_includeFull
-$_includeMatchers
-$_excludeFull
-$_excludeMatchers
-    ''';
-  }
-}
diff --git a/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart
index 3544330..560cc59 100644
--- a/lib/src/config_provider/spec_utils.dart
+++ b/lib/src/config_provider/spec_utils.dart
@@ -12,9 +12,9 @@
 
 import '../strings.dart' as strings;
 import './config.dart';
-import 'filter.dart';
+import 'declaration.dart';
 
-var _logger = Logger('config_provider/utils');
+var _logger = Logger('config_provider:spec_utils.dart');
 
 bool booleanExtractor(dynamic value) => value as bool;
 
@@ -166,13 +166,15 @@
   if (value is String) {
     return true;
   } else {
-    _logger.severe("Expected value of key '${strings.output}' to be a String.");
+    _logger.severe("Expected value of key '$name' to be a String.");
     return false;
   }
 }
 
-Filter filterExtractor(dynamic yamlMap) {
+Declaration declarationConfigExtractor(dynamic yamlMap) {
   List<String> includeMatchers, includeFull, excludeMatchers, excludeFull;
+  String prefix;
+  Map<String, String> prefixReplacement;
 
   final include = yamlMap[strings.include] as YamlMap;
   if (include != null) {
@@ -186,21 +188,29 @@
     excludeFull = (exclude[strings.names] as YamlList)?.cast<String>();
   }
 
-  return Filter(
+  prefix = yamlMap[strings.prefix] as String;
+
+  prefixReplacement =
+      (yamlMap[strings.prefix_replacement] as YamlMap)?.cast<String, String>();
+
+  return Declaration(
     includeMatchers: includeMatchers,
     includeFull: includeFull,
     excludeMatchers: excludeMatchers,
     excludeFull: excludeFull,
+    globalPrefix: prefix,
+    prefixReplacement: prefixReplacement,
   );
 }
 
-bool filterValidator(String name, dynamic value) {
+bool declarationConfigValidator(String name, dynamic value) {
   var _result = true;
   if (value is YamlMap) {
     for (final key in value.keys) {
       if (key == strings.include || key == strings.exclude) {
         if (value[key] is! YamlMap) {
           _logger.severe("Expected '$name -> $key' to be a Map.");
+          _result = false;
         }
         for (final subkey in value[key].keys) {
           if (subkey == strings.matches || subkey == strings.names) {
@@ -213,6 +223,24 @@
             _logger.severe("Unknown key '$subkey' in '$name -> $key'.");
           }
         }
+      } else if (key == strings.prefix) {
+        if (value[key] is! String) {
+          _logger.severe("Expected '$name -> $key' to be a String.");
+          _result = false;
+        }
+      } else if (key == strings.prefix_replacement) {
+        if (value[key] is! YamlMap) {
+          _logger.severe("Expected '$name -> $key' to be a Map.");
+          _result = false;
+        } else {
+          for (final subkey in value[key].keys) {
+            if (value[key][subkey] is! String) {
+              _logger.severe(
+                  "Expected '$name -> $key -> $subkey' to be a String.");
+              _result = false;
+            }
+          }
+        }
       } else {
         _logger.severe("Unknown key '$key' in '$name'.");
         _result = false;
@@ -241,6 +269,17 @@
   }
 }
 
+String stringExtractor(dynamic value) => value as String;
+
+bool nonEmptyStringValidator(String name, dynamic value) {
+  if (value is String && value.isNotEmpty) {
+    return true;
+  } else {
+    _logger.severe("Expected value of key '$name' to be a non-empty String.");
+    return false;
+  }
+}
+
 String commentExtractor(dynamic value) => value as String;
 
 bool commentValidator(String name, dynamic value) {
diff --git a/lib/src/header_parser/clang_bindings/clang_bindings.dart b/lib/src/header_parser/clang_bindings/clang_bindings.dart
index 546c8dc..e71a162 100644
--- a/lib/src/header_parser/clang_bindings/clang_bindings.dart
+++ b/lib/src/header_parser/clang_bindings/clang_bindings.dart
@@ -7,8 +7,8 @@
 ffi.DynamicLibrary _dylib;
 
 /// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib) {
-  _dylib = dylib;
+void init(ffi.DynamicLibrary __dylib) {
+  _dylib = __dylib;
 }
 
 /// Describes how the traversal of the children of a particular cursor should
@@ -35,9 +35,9 @@
   @ffi.Int32()
   int xdata;
 
-  ffi.Pointer<ffi.Void> _data_item_0;
-  ffi.Pointer<ffi.Void> _data_item_1;
-  ffi.Pointer<ffi.Void> _data_item_2;
+  ffi.Pointer<ffi.Void> _exp_workaround_data_item_0;
+  ffi.Pointer<ffi.Void> _exp_workaround_data_item_1;
+  ffi.Pointer<ffi.Void> _exp_workaround_data_item_2;
 
   /// Helper for array `data`.
   ArrayHelper_CXCursor_data_level0 get data =>
@@ -64,11 +64,11 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        return _struct._data_item_0;
+        return _struct._exp_workaround_data_item_0;
       case 1:
-        return _struct._data_item_1;
+        return _struct._exp_workaround_data_item_1;
       case 2:
-        return _struct._data_item_2;
+        return _struct._exp_workaround_data_item_2;
       default:
         throw Exception('Invalid Array Helper generated.');
     }
@@ -78,13 +78,13 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        _struct._data_item_0 = value;
+        _struct._exp_workaround_data_item_0 = value;
         break;
       case 1:
-        _struct._data_item_1 = value;
+        _struct._exp_workaround_data_item_1 = value;
         break;
       case 2:
-        _struct._data_item_2 = value;
+        _struct._exp_workaround_data_item_2 = value;
         break;
       default:
         throw Exception('Invalid Array Helper generated.');
@@ -769,8 +769,8 @@
 
 /// Identifies a specific source location within a translation unit.
 class CXSourceLocation extends ffi.Struct {
-  ffi.Pointer<ffi.Void> _ptr_data_item_0;
-  ffi.Pointer<ffi.Void> _ptr_data_item_1;
+  ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_0;
+  ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_1;
 
   /// Helper for array `ptr_data`.
   ArrayHelper_CXSourceLocation_ptr_data_level0 get ptr_data =>
@@ -799,9 +799,9 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        return _struct._ptr_data_item_0;
+        return _struct._exp_workaround_ptr_data_item_0;
       case 1:
-        return _struct._ptr_data_item_1;
+        return _struct._exp_workaround_ptr_data_item_1;
       default:
         throw Exception('Invalid Array Helper generated.');
     }
@@ -811,10 +811,10 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        _struct._ptr_data_item_0 = value;
+        _struct._exp_workaround_ptr_data_item_0 = value;
         break;
       case 1:
-        _struct._ptr_data_item_1 = value;
+        _struct._exp_workaround_ptr_data_item_1 = value;
         break;
       default:
         throw Exception('Invalid Array Helper generated.');
@@ -824,8 +824,8 @@
 
 /// Identifies a half-open character range in the source code.
 class CXSourceRange extends ffi.Struct {
-  ffi.Pointer<ffi.Void> _ptr_data_item_0;
-  ffi.Pointer<ffi.Void> _ptr_data_item_1;
+  ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_0;
+  ffi.Pointer<ffi.Void> _exp_workaround_ptr_data_item_1;
 
   /// Helper for array `ptr_data`.
   ArrayHelper_CXSourceRange_ptr_data_level0 get ptr_data =>
@@ -857,9 +857,9 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        return _struct._ptr_data_item_0;
+        return _struct._exp_workaround_ptr_data_item_0;
       case 1:
-        return _struct._ptr_data_item_1;
+        return _struct._exp_workaround_ptr_data_item_1;
       default:
         throw Exception('Invalid Array Helper generated.');
     }
@@ -869,10 +869,10 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        _struct._ptr_data_item_0 = value;
+        _struct._exp_workaround_ptr_data_item_0 = value;
         break;
       case 1:
-        _struct._ptr_data_item_1 = value;
+        _struct._exp_workaround_ptr_data_item_1 = value;
         break;
       default:
         throw Exception('Invalid Array Helper generated.');
@@ -959,8 +959,8 @@
   @ffi.Int32()
   int kind;
 
-  ffi.Pointer<ffi.Void> _data_item_0;
-  ffi.Pointer<ffi.Void> _data_item_1;
+  ffi.Pointer<ffi.Void> _exp_workaround_data_item_0;
+  ffi.Pointer<ffi.Void> _exp_workaround_data_item_1;
 
   /// Helper for array `data`.
   ArrayHelper_CXType_data_level0 get data =>
@@ -987,9 +987,9 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        return _struct._data_item_0;
+        return _struct._exp_workaround_data_item_0;
       case 1:
-        return _struct._data_item_1;
+        return _struct._exp_workaround_data_item_1;
       default:
         throw Exception('Invalid Array Helper generated.');
     }
@@ -999,10 +999,10 @@
     _checkBounds(index);
     switch (_absoluteIndex + index) {
       case 0:
-        _struct._data_item_0 = value;
+        _struct._exp_workaround_data_item_0 = value;
         break;
       case 1:
-        _struct._data_item_1 = value;
+        _struct._exp_workaround_data_item_1 = value;
         break;
       default:
         throw Exception('Invalid Array Helper generated.');
@@ -1150,12 +1150,6 @@
   int Length;
 }
 
-typedef ModifiedCXCursorVisitor = ffi.Int32 Function(
-  ffi.Pointer<CXCursor>,
-  ffi.Pointer<CXCursor>,
-  ffi.Pointer<ffi.Void>,
-);
-
 ffi.Pointer<CXCursor> clang_Cursor_getArgument_wrap(
   ffi.Pointer<CXCursor> cursor,
   int i,
@@ -2001,11 +1995,17 @@
   int options,
 );
 
+typedef ModifiedCXCursorVisitor_1 = ffi.Int32 Function(
+  ffi.Pointer<CXCursor>,
+  ffi.Pointer<CXCursor>,
+  ffi.Pointer<ffi.Void>,
+);
+
 /// Visitor is a function pointer with parameters having pointers to cxcursor
 /// instead of cxcursor by default.
 int clang_visitChildren_wrap(
   ffi.Pointer<CXCursor> parent,
-  ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
+  ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
   ffi.Pointer<ffi.Void> clientData,
 ) {
   return _clang_visitChildren_wrap(
@@ -2021,12 +2021,12 @@
 
 typedef _c_clang_visitChildren_wrap = ffi.Uint32 Function(
   ffi.Pointer<CXCursor> parent,
-  ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
+  ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
   ffi.Pointer<ffi.Void> clientData,
 );
 
 typedef _dart_clang_visitChildren_wrap = int Function(
   ffi.Pointer<CXCursor> parent,
-  ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor>> _modifiedVisitor,
+  ffi.Pointer<ffi.NativeFunction<ModifiedCXCursorVisitor_1>> _modifiedVisitor,
   ffi.Pointer<ffi.Void> clientData,
 );
diff --git a/lib/src/header_parser/includer.dart b/lib/src/header_parser/includer.dart
index 23698a5..f0ab13c 100644
--- a/lib/src/header_parser/includer.dart
+++ b/lib/src/header_parser/includer.dart
@@ -2,25 +2,23 @@
 // 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:meta/meta.dart';
+import 'package:ffigen/src/code_generator.dart';
 import 'package:path/path.dart' as p;
 import 'data.dart';
 
 /// Utility functions to check whether a binding should be parsed or not
-/// based on filters and if a binding is seen already.
+/// based on filters.
 
-// Stores binding names already scene.
-Set<String> _structs = {};
-Set<String> _functions = {};
-Set<String> _enumClass = {};
-Set<String> _typedefC = {};
+// Stores binding names already scene. Mp key is same as their original name.
+Map<String, Struc> _structs = {};
+Map<String, Func> _functions = {};
+Map<String, EnumClass> _enumClass = {};
 
 bool shouldIncludeStruct(String name) {
-  if (_structs.contains(name) || name == '') {
+  if (_structs.containsKey(name) || name == '') {
     return false;
-  } else if (config.structFilters == null ||
-      config.structFilters.shouldInclude(name)) {
-    _structs.add(name);
+  } else if (config.structDecl == null ||
+      config.structDecl.shouldInclude(name)) {
     return true;
   } else {
     return false;
@@ -28,11 +26,10 @@
 }
 
 bool shouldIncludeFunc(String name) {
-  if (_functions.contains(name) || name == '') {
+  if (_functions.containsKey(name) || name == '') {
     return false;
-  } else if (config.functionFilters == null ||
-      config.functionFilters.shouldInclude(name)) {
-    _functions.add(name);
+  } else if (config.functionDecl == null ||
+      config.functionDecl.shouldInclude(name)) {
     return true;
   } else {
     return false;
@@ -40,11 +37,10 @@
 }
 
 bool shouldIncludeEnumClass(String name) {
-  if (_enumClass.contains(name) || name == '') {
+  if (_enumClass.containsKey(name) || name == '') {
     return false;
-  } else if (config.enumClassFilters == null ||
-      config.enumClassFilters.shouldInclude(name)) {
-    _enumClass.add(name);
+  } else if (config.enumClassDecl == null ||
+      config.enumClassDecl.shouldInclude(name)) {
     return true;
   } else {
     return false;
@@ -72,24 +68,38 @@
   }
 }
 
-bool isUnseenTypedefC(String name, {@required bool addToSeen}) {
-  if (_typedefC.contains(name)) {
-    return false;
-  } else {
-    if (addToSeen) {
-      _typedefC.add(name);
-    }
-    return true;
-  }
+bool isSeenStruc(String originalName) {
+  return _structs.containsKey(originalName);
 }
 
-bool isUnseenStruct(String name, {@required bool addToSeen}) {
-  if (_structs.contains(name)) {
-    return false;
-  } else {
-    if (addToSeen) {
-      _structs.add(name);
-    }
-    return true;
-  }
+void addStrucToSeen(String originalName, Struc struc) {
+  _structs[originalName] = struc;
+}
+
+Struc getSeenStruc(String originalName) {
+  return _structs[originalName];
+}
+
+bool isSeenFunc(String originalName) {
+  return _functions.containsKey(originalName);
+}
+
+void addFuncToSeen(String originalName, Func func) {
+  _functions[originalName] = func;
+}
+
+Func getSeenFunc(String originalName) {
+  return _functions[originalName];
+}
+
+bool isSeenEnumClass(String originalName) {
+  return _enumClass.containsKey(originalName);
+}
+
+void addEnumClassToSeen(String originalName, EnumClass enumClass) {
+  _enumClass[originalName] = enumClass;
+}
+
+EnumClass getSeenEnumClass(String originalName) {
+  return _enumClass[originalName];
 }
diff --git a/lib/src/header_parser/parser.dart b/lib/src/header_parser/parser.dart
index eac3c93..f50e2e5 100644
--- a/lib/src/header_parser/parser.dart
+++ b/lib/src/header_parser/parser.dart
@@ -20,7 +20,11 @@
 
   final bindings = parseToBindings();
 
-  final library = Library(bindings: bindings);
+  final library = Library(
+    bindings: bindings,
+    initFunctionIdentifier: data.config.initFunctionName,
+    header: data.config.preamble,
+  );
 
   if (sort) {
     library.sort();
@@ -32,7 +36,7 @@
 //           BELOW FUNCTIONS ARE MEANT FOR INTERNAL USE AND TESTING
 // ===================================================================================
 
-var _logger = Logger('parser:parser');
+var _logger = Logger('header_parser:parser.dart');
 
 /// initialises parser, clears any previous values.
 void initParser(Config c) {
diff --git a/lib/src/header_parser/sub_parsers/enumdecl_parser.dart b/lib/src/header_parser/sub_parsers/enumdecl_parser.dart
index c3e5a54..25266e1 100644
--- a/lib/src/header_parser/sub_parsers/enumdecl_parser.dart
+++ b/lib/src/header_parser/sub_parsers/enumdecl_parser.dart
@@ -5,13 +5,14 @@
 import 'dart:ffi';
 
 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;
 import '../includer.dart';
 import '../utils.dart';
 
-var _logger = Logger('parser:enumdecl_parser');
+var _logger = Logger('header_parser:enumdecl_parser.dart');
 
 /// Temporarily holds a enumClass before its returned by [parseEnumDeclaration].
 EnumClass _enumClass;
@@ -28,12 +29,13 @@
   final enumName = name ?? cursor.spelling();
   if (enumName == '') {
     _logger.finest('unnamed enum declaration');
-  } else if (shouldIncludeEnumClass(enumName)) {
+  } else if (shouldIncludeEnumClass(enumName) && !isSeenEnumClass(enumName)) {
     _logger.fine('++++ Adding Enum: ${cursor.completeStringRepr()}');
     _enumClass = EnumClass(
       dartDoc: getCursorDocComment(cursor),
-      name: enumName,
+      name: config.enumClassDecl.getPrefixedName(enumName),
     );
+    addEnumClassToSeen(enumName, _enumClass);
     _addEnumConstant(cursor);
   }
 
diff --git a/lib/src/header_parser/sub_parsers/functiondecl_parser.dart b/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
index 3afb7b7..98b93d0 100644
--- a/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
+++ b/lib/src/header_parser/sub_parsers/functiondecl_parser.dart
@@ -5,13 +5,14 @@
 import 'dart:ffi';
 
 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;
 import '../includer.dart';
 import '../utils.dart';
 
-var _logger = Logger('parser:functiondecl_parser');
+var _logger = Logger('header_parser:functiondecl_parser.dart');
 
 /// Temporarily holds a function before its returned by [parseFunctionDeclaration].
 Func _func;
@@ -22,8 +23,8 @@
   structByValueParameter = false;
   unimplementedParameterType = false;
 
-  final name = cursor.spelling();
-  if (shouldIncludeFunc(name)) {
+  final funcName = cursor.spelling();
+  if (shouldIncludeFunc(funcName) && !isSeenFunc(funcName)) {
     _logger.fine('++++ Adding Function: ${cursor.completeStringRepr()}');
 
     final rt = _getFunctionReturnType(cursor);
@@ -34,25 +35,27 @@
       _logger.fine(
           '---- Removed Function, reason: struct pass/return by value: ${cursor.completeStringRepr()}');
       _logger.warning(
-          "Skipped Function '$name', struct pass/return by value not supported.");
+          "Skipped Function '$funcName', struct pass/return by value not supported.");
       return null; // Returning null so that [addToBindings] function excludes this.
     }
 
-    if (rt.getBaseBroadType() == BroadType.Unimplemented ||
+    if (rt.getBaseType().broadType == BroadType.Unimplemented ||
         unimplementedParameterType) {
       _logger.fine(
           '---- Removed Function, reason: unsupported return type or parameter type: ${cursor.completeStringRepr()}');
       _logger.warning(
-          "Skipped Function '$name', function has unsupported return type or parameter type.");
+          "Skipped Function '$funcName', function has unsupported return type or parameter type.");
       return null; // Returning null so that [addToBindings] function excludes this.
     }
 
     _func = Func(
       dartDoc: getCursorDocComment(cursor),
-      name: name,
+      name: config.functionDecl.getPrefixedName(funcName),
+      lookupSymbolName: funcName,
       returnType: rt,
       parameters: parameters,
     );
+    addFuncToSeen(funcName, _func);
   }
 
   return _func;
@@ -77,7 +80,7 @@
     //TODO(3): Remove this when support for Structs by value arrives.
     if (pt.broadType == BroadType.Struct) {
       structByValueParameter = true;
-    } else if (pt.getBaseBroadType() == BroadType.Unimplemented) {
+    } else if (pt.getBaseType().broadType == BroadType.Unimplemented) {
       unimplementedParameterType = true;
     }
 
diff --git a/lib/src/header_parser/sub_parsers/structdecl_parser.dart b/lib/src/header_parser/sub_parsers/structdecl_parser.dart
index d7c9dc4..a71f69e 100644
--- a/lib/src/header_parser/sub_parsers/structdecl_parser.dart
+++ b/lib/src/header_parser/sub_parsers/structdecl_parser.dart
@@ -12,7 +12,7 @@
 import '../includer.dart';
 import '../utils.dart';
 
-var _logger = Logger('parser:structdecl_parser');
+var _logger = Logger('header_parser:structdecl_parser.dart');
 
 /// Temporarily holds a struc before its returned by [parseStructDeclaration].
 Struc _struc;
@@ -24,11 +24,9 @@
   /// Optionally provide name (useful in case struct is inside a typedef).
   String name,
 
-  /// Option to override shouldInclude methods. (Useful in case of extracting
-  /// structs when they are passed/returned by an included function.)
-  ///
-  /// Check if binding is not already included before setting this to true.
-  bool doInclude = false,
+  /// Option to ignore struct filter (Useful in case of extracting structs
+  /// when they are passed/returned by an included function.)
+  bool ignoreFilter = false,
 }) {
   _struc = null;
   final structName = name ?? cursor.spelling();
@@ -36,16 +34,19 @@
   if (structName == '') {
     _logger.finest('unnamed structure or typedef structure declaration');
     return null;
-  } else if (doInclude || shouldIncludeStruct(structName)) {
+  } else if ((ignoreFilter || shouldIncludeStruct(structName)) &&
+      (!isSeenStruc(structName))) {
     _logger.fine(
         '++++ Adding Structure: structName: ${structName}, ${cursor.completeStringRepr()}');
 
-    final members = _getMembers(cursor, structName);
     _struc = Struc(
+      name: config.structDecl.getPrefixedName(structName),
       dartDoc: getCursorDocComment(cursor),
-      name: structName,
-      members: members,
     );
+    // Adding to seen here to stop recursion if a struct has itself as a
+    // member, members are updated later.
+    addStrucToSeen(structName, _struc);
+    _struc.members = _getMembers(cursor, structName);
   }
 
   return _struc;
@@ -72,19 +73,19 @@
         '---- Removed Struct members, reason: struct has array members ${cursor.completeStringRepr()}');
     _logger.warning(
         'Removed All Struct Members from: $structName, Array members not supported');
-    return null;
+    return [];
   } else if (nestedStructMember) {
     _logger.fine(
         '---- Removed Struct members, reason: struct has struct members ${cursor.completeStringRepr()}');
     _logger.warning(
         "Removed All Struct Members from '$structName', Nested Structures not supported.");
-    return null;
+    return [];
   } else if (unimplementedMemberType) {
     _logger.fine(
         '---- Removed Struct members, reason: member with unimplementedtype ${cursor.completeStringRepr()}');
     _logger.warning(
         "Removed All Struct Members from '$structName', struct member has an unsupported type.");
-    return null;
+    return [];
   }
 
   return _members;
@@ -119,7 +120,7 @@
         }
       }
 
-      if (mt.getBaseBroadType() == BroadType.Unimplemented) {
+      if (mt.getBaseType().broadType == BroadType.Unimplemented) {
         unimplementedMemberType = true;
       }
 
diff --git a/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart b/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart
index c68b5e3..30ec2ab 100644
--- a/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart
+++ b/lib/src/header_parser/sub_parsers/typedefdecl_parser.dart
@@ -12,7 +12,7 @@
 import '../sub_parsers/structdecl_parser.dart';
 import '../utils.dart';
 
-var _logger = Logger('parser:typedefdecl_parser');
+var _logger = Logger('header_parser:typedefdecl_parser.dart');
 
 /// Temporarily holds a binding before its returned by [parseTypedefDeclaration].
 Binding _binding;
diff --git a/lib/src/header_parser/translation_unit_parser.dart b/lib/src/header_parser/translation_unit_parser.dart
index 8632b25..a1b794b 100644
--- a/lib/src/header_parser/translation_unit_parser.dart
+++ b/lib/src/header_parser/translation_unit_parser.dart
@@ -15,7 +15,7 @@
 import 'sub_parsers/typedefdecl_parser.dart';
 import 'utils.dart';
 
-var _logger = Logger('parser:root_parser');
+var _logger = Logger('header_parser:translation_unit_parser.dart');
 
 List<Binding> _bindings;
 
diff --git a/lib/src/header_parser/type_extractor/extractor.dart b/lib/src/header_parser/type_extractor/extractor.dart
index 9584cea..65fd6f0 100644
--- a/lib/src/header_parser/type_extractor/extractor.dart
+++ b/lib/src/header_parser/type_extractor/extractor.dart
@@ -16,7 +16,7 @@
 import '../type_extractor/cxtypekindmap.dart';
 import '../utils.dart';
 
-var _logger = Logger('parser:extractor');
+var _logger = Logger('header_parser:extractor.dart');
 const _padding = '  ';
 
 /// Converts cxtype to a typestring code_generator can accept.
@@ -100,12 +100,20 @@
         structName = cxtype.spelling();
       }
 
-      type = Type.struct(structName);
+      final fixedStructName = config.structDecl.getPrefixedName(structName);
 
       // Also add a struct binding, if its unseen.
-      if (isUnseenStruct(structName, addToSeen: true)) {
-        addToBindings(
-            parseStructDeclaration(cursor, name: structName, doInclude: true));
+      // TODO(23): Check if we should auto add struct.
+      if (isSeenStruc(structName)) {
+        type = Type.struct(getSeenStruc(structName));
+      } else {
+        final struc = parseStructDeclaration(cursor,
+            name: fixedStructName, ignoreFilter: true);
+        type = Type.struct(struc);
+        // Add to bindings.
+        addToBindings(struc);
+        // Add to seen.
+        addStrucToSeen(structName, struc);
       }
 
       cxtype.dispose();
@@ -127,25 +135,34 @@
 
   // Set a name for typedefc incase it was null or empty.
   if (name == null || name == '') {
-    name = _getNextUniqueString('_typedefC_noname');
+    name = _getNextUniqueString('_typedefC');
+  } else {
+    name = _getNextUniqueString(name);
   }
+  final _parameters = <Parameter>[];
+  final totalArgs = clang.clang_getNumArgTypes_wrap(cxtype);
+  for (var i = 0; i < totalArgs; i++) {
+    final t = clang.clang_getArgType_wrap(cxtype, i);
+    final pt = t.toCodeGenTypeAndDispose();
 
-  if (isUnseenTypedefC(name, addToSeen: true)) {
-    final typedefC = TypedefC(
-      name: name,
-      returnType:
-          clang.clang_getResultType_wrap(cxtype).toCodeGenTypeAndDispose(),
-    );
-    final totalArgs = clang.clang_getNumArgTypes_wrap(cxtype);
-    for (var i = 0; i < totalArgs; i++) {
-      final t = clang.clang_getArgType_wrap(cxtype, i);
-      typedefC.parameters.add(
-        Parameter(name: '', type: t.toCodeGenTypeAndDispose()),
-      );
+    if (pt.broadType == BroadType.Struct) {
+      return Type.unimplemented('Struct by value in function parameter.');
+    } else if (pt.broadType == BroadType.Unimplemented) {
+      return Type.unimplemented('Function parameter has an unsupported type.');
     }
-    addToBindings(typedefC);
+
+    _parameters.add(
+      Parameter(name: '', type: pt),
+    );
   }
-  return Type.nativeFunc(name);
+  final typedefC = TypedefC(
+    name: name,
+    parameters: _parameters,
+    returnType:
+        clang.clang_getResultType_wrap(cxtype).toCodeGenTypeAndDispose(),
+  );
+
+  return Type.nativeFunc(typedefC);
 }
 
 /// Generate a unique string for naming in [TypedefC].
diff --git a/lib/src/strings.dart b/lib/src/strings.dart
index a03aa97..27e1d50 100644
--- a/lib/src/strings.dart
+++ b/lib/src/strings.dart
@@ -19,6 +19,8 @@
 // Sub-fields of Declarations.
 const include = 'include';
 const exclude = 'exclude';
+const prefix = 'prefix';
+const prefix_replacement = 'prefix-replacement';
 
 // Sub-fields of include/exclude.
 const matches = 'matches'; // regex
@@ -68,6 +70,10 @@
 // Contains all possibe comment types.
 const commentTypeSet = {brief, full, none};
 
+// Library input.
+const initFunctionName = 'init-function-name';
+const preamble = 'preamble';
+
 // Dynamic library names.
 const libclang_dylib_linux = 'libwrapped_clang.so';
 const libclang_dylib_macos = 'libwrapped_clang.dylib';
diff --git a/test/code_generator_test.dart b/test/code_generator_test.dart
index 4312837..cddaab4 100644
--- a/test/code_generator_test.dart
+++ b/test/code_generator_test.dart
@@ -14,6 +14,7 @@
         bindings: [
           Func(
             name: 'noParam',
+            lookupSymbolName: 'noParam',
             dartDoc: 'Just a test function\nheres another line',
             returnType: Type.nativeType(
               SupportedNativeType.Int32,
@@ -21,6 +22,7 @@
           ),
           Func(
             name: 'withPrimitiveParam',
+            lookupSymbolName: 'withPrimitiveParam',
             parameters: [
               Parameter(
                 name: 'a',
@@ -41,6 +43,7 @@
           ),
           Func(
             name: 'withPointerParam',
+            lookupSymbolName: 'withPointerParam',
             parameters: [
               Parameter(
                 name: 'a',
@@ -86,8 +89,8 @@
 ffi.DynamicLibrary _dylib;
 
 /// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
-  _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary){
+  _dylib = dynamicLibrary;
 }
 /// Just a test function
 /// heres another line
@@ -237,8 +240,8 @@
 ffi.DynamicLibrary _dylib;
 
 /// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
-  _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary){
+  _dylib = dynamicLibrary;
 }
 /// Just a test struct
 /// heres another line
@@ -279,40 +282,42 @@
     });
 
     test('Function and Struct Binding (pointer to Struct)', () {
+      final struct_some = Struc(
+        name: 'SomeStruc',
+        members: [
+          Member(
+            name: 'a',
+            type: Type.nativeType(
+              SupportedNativeType.Int32,
+            ),
+          ),
+          Member(
+            name: 'b',
+            type: Type.nativeType(
+              SupportedNativeType.Double,
+            ),
+          ),
+          Member(
+            name: 'c',
+            type: Type.nativeType(
+              SupportedNativeType.Char,
+            ),
+          ),
+        ],
+      );
       final library = Library(
         bindings: [
-          Struc(
-            name: 'SomeStruc',
-            members: [
-              Member(
-                name: 'a',
-                type: Type.nativeType(
-                  SupportedNativeType.Int32,
-                ),
-              ),
-              Member(
-                name: 'b',
-                type: Type.nativeType(
-                  SupportedNativeType.Double,
-                ),
-              ),
-              Member(
-                name: 'c',
-                type: Type.nativeType(
-                  SupportedNativeType.Char,
-                ),
-              ),
-            ],
-          ),
+          struct_some,
           Func(
             name: 'someFunc',
+            lookupSymbolName: 'someFunc',
             parameters: [
               Parameter(
                 name: 'some',
                 type: Type.pointer(
                   Type.pointer(
                     Type.struct(
-                      'SomeStruc',
+                      struct_some,
                     ),
                   ),
                 ),
@@ -320,7 +325,7 @@
             ],
             returnType: Type.pointer(
               Type.struct(
-                'SomeStruc',
+                struct_some,
               ),
             ),
           ),
@@ -343,8 +348,8 @@
 ffi.DynamicLibrary _dylib;
 
 /// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
-  _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary){
+  _dylib = dynamicLibrary;
 }
 class SomeStruc extends ffi.Struct{
   @ffi.Int32()
@@ -388,30 +393,34 @@
     });
 
     test('global (primitives, pointers, pointer to struct)', () {
+      final struc_some = Struc(
+        name: 'Some',
+      );
       final library = Library(
         bindings: [
           Global(
             name: 'test1',
+            lookupSymbolName: 'test1',
             type: Type.nativeType(
               SupportedNativeType.Int32,
             ),
           ),
           Global(
             name: 'test2',
+            lookupSymbolName: 'test2',
             type: Type.pointer(
               Type.nativeType(
                 SupportedNativeType.Float,
               ),
             ),
           ),
-          Struc(
-            name: 'Some',
-          ),
+          struc_some,
           Global(
             name: 'test5',
+            lookupSymbolName: 'test5',
             type: Type.pointer(
               Type.struct(
-                'Some',
+                struc_some,
               ),
             ),
           ),
@@ -434,8 +443,8 @@
 ffi.DynamicLibrary _dylib;
 
 /// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
-  _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary){
+  _dylib = dynamicLibrary;
 }
 final int test1 = _dylib.lookup<ffi.Int32>('test1').value;
 
@@ -493,8 +502,8 @@
 ffi.DynamicLibrary _dylib;
 
 /// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
-  _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary){
+  _dylib = dynamicLibrary;
 }
 const int test1 = 20;
 
@@ -511,83 +520,6 @@
       }
     });
 
-    test('TypedefC (primitive, pointers, pointer to struct)', () {
-      final library = Library(
-        bindings: [
-          TypedefC(
-            dartDoc: 'just a test',
-            name: 'test1',
-            returnType: Type.nativeType(
-              SupportedNativeType.Int32,
-            ),
-          ),
-          Struc(name: 'SomeStruct'),
-          TypedefC(
-            name: 'test2',
-            returnType: Type.pointer(
-              Type.nativeType(
-                SupportedNativeType.Int32,
-              ),
-            ),
-            parameters: [
-              Parameter(
-                name: 'param1',
-                type: Type.pointer(
-                  Type.struct('SomeStruct'),
-                ),
-              ),
-              Parameter(
-                name: 'param2',
-                type: Type.nativeType(
-                  SupportedNativeType.Char,
-                ),
-              ),
-            ],
-          ),
-        ],
-      );
-
-      final gen = library.generate();
-
-      // Writing to file for debug purpose.
-      final file =
-          File('test/debug_generated/typedef-Binding-test-output.dart');
-      try {
-        expect(gen, '''/// AUTO GENERATED FILE, DO NOT EDIT.
-///
-/// Generated by `package:ffigen`.
-import 'dart:ffi' as ffi;
-
-/// Holds the Dynamic library.
-ffi.DynamicLibrary _dylib;
-
-/// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
-  _dylib = dylib;
-}
-/// just a test
-typedef test1 = ffi.Int32 Function(
-);
-
-class SomeStruct extends ffi.Struct{
-}
-
-typedef test2 = ffi.Pointer<ffi.Int32> Function(
-  ffi.Pointer<SomeStruct> param1,
-  ffi.Uint8 param2,
-);
-
-''');
-        if (file.existsSync()) {
-          file.delete();
-        }
-      } catch (e) {
-        file.writeAsStringSync(gen);
-        print('Failed test, Debug output: ${file.absolute?.path}');
-        rethrow;
-      }
-    });
-
     test('enum_class', () {
       final library = Library(
         bindings: [
@@ -621,8 +553,8 @@
 ffi.DynamicLibrary _dylib;
 
 /// Initialises the Dynamic library.
-void init(ffi.DynamicLibrary dylib){
-  _dylib = dylib;
+void init(ffi.DynamicLibrary dynamicLibrary){
+  _dylib = dynamicLibrary;
 }
 /// test line 1
 /// test line 2
@@ -642,5 +574,208 @@
         rethrow;
       }
     });
+    test('Internal conflict resolution', () {
+      final library = Library(
+        initFunctionIdentifier: 'init_dylib',
+        bindings: [
+          Func(
+            name: 'test',
+            lookupSymbolName: 'test',
+            returnType: Type.nativeType(SupportedNativeType.Void),
+          ),
+          Func(
+            name: '_test',
+            lookupSymbolName: '_test',
+            returnType: Type.nativeType(SupportedNativeType.Void),
+          ),
+          Func(
+            name: '_c_test',
+            lookupSymbolName: '_c_test',
+            returnType: Type.nativeType(SupportedNativeType.Void),
+          ),
+          Func(
+            name: '_dart_test',
+            lookupSymbolName: '_dart_test',
+            returnType: Type.nativeType(SupportedNativeType.Void),
+          ),
+          Struc(
+            name: '_Test',
+            members: [
+              Member(
+                name: 'array',
+                type: Type.constantArray(
+                  2,
+                  Type.nativeType(
+                    SupportedNativeType.Int8,
+                  ),
+                ),
+              ),
+            ],
+          ),
+          Struc(name: 'ArrayHelperPrefixCollisionTest'),
+          Func(
+            name: 'Test',
+            lookupSymbolName: 'Test',
+            returnType: Type.nativeType(SupportedNativeType.Void),
+          ),
+          EnumClass(name: '_c_Test'),
+          EnumClass(name: 'init_dylib'),
+        ],
+      );
+
+      final gen = library.generate();
+
+      // Writing to file for debug purpose.
+      final file = File(
+        'test/debug_generated/internal-conflict-resolution.dart',
+      );
+      try {
+        expect(gen, r'''/// AUTO GENERATED FILE, DO NOT EDIT.
+///
+/// Generated by `package:ffigen`.
+import 'dart:ffi' as ffi;
+
+/// Holds the Dynamic library.
+ffi.DynamicLibrary _dylib;
+
+/// Initialises the Dynamic library.
+void init_dylib_1(ffi.DynamicLibrary dynamicLibrary){
+  _dylib = dynamicLibrary;
+}
+void test(
+) {
+  return _test_1(
+  );
+}
+
+final _dart_test_1 _test_1 = _dylib.lookupFunction<_c_test_1,_dart_test_1>('test');
+
+typedef _c_test_1 = ffi.Void Function(
+);
+
+typedef _dart_test_1 = void Function(
+);
+
+void _test(
+) {
+  return __test(
+  );
+}
+
+final _dart__test __test = _dylib.lookupFunction<_c__test,_dart__test>('_test');
+
+typedef _c__test = ffi.Void Function(
+);
+
+typedef _dart__test = void Function(
+);
+
+void _c_test(
+) {
+  return __c_test(
+  );
+}
+
+final _dart__c_test __c_test = _dylib.lookupFunction<_c__c_test,_dart__c_test>('_c_test');
+
+typedef _c__c_test = ffi.Void Function(
+);
+
+typedef _dart__c_test = void Function(
+);
+
+void _dart_test(
+) {
+  return __dart_test(
+  );
+}
+
+final _dart__dart_test __dart_test = _dylib.lookupFunction<_c__dart_test,_dart__dart_test>('_dart_test');
+
+typedef _c__dart_test = ffi.Void Function(
+);
+
+typedef _dart__dart_test = void Function(
+);
+
+class _Test extends ffi.Struct{
+  @ffi.Int8()
+  int _exp_workaround_array_item_0;
+  @ffi.Int8()
+  int _exp_workaround_array_item_1;
+/// Helper for array `array`.
+ArrayHelper1__Test_array_level0 get array => ArrayHelper1__Test_array_level0(this, [2], 0, 0);
+}
+
+/// Helper for array `array` in struct `_Test`.
+class ArrayHelper1__Test_array_level0{
+final _Test _struct;
+final List<int> dimensions;
+final int level;
+final int _absoluteIndex;
+int get length => dimensions[level];
+ArrayHelper1__Test_array_level0(this._struct, this.dimensions, this.level, this._absoluteIndex);
+  void _checkBounds(int index) {
+    if (index >= length || index < 0) {
+      throw RangeError('Dimension $level: index not in range 0..${length} exclusive.');
+    }
+  }
+  int operator[](int index){
+_checkBounds(index);
+switch(_absoluteIndex+index){
+case 0:
+  return _struct._exp_workaround_array_item_0;
+case 1:
+  return _struct._exp_workaround_array_item_1;
+default:
+  throw Exception('Invalid Array Helper generated.');}
+}
+void operator[]=(int index, int value){
+_checkBounds(index);
+switch(_absoluteIndex+index){
+case 0:
+  _struct._exp_workaround_array_item_0 = value;
+  break;
+case 1:
+  _struct._exp_workaround_array_item_1 = value;
+  break;
+default:
+  throw Exception('Invalid Array Helper generated.');
+}
+}
+}
+class ArrayHelperPrefixCollisionTest extends ffi.Struct{
+}
+
+void Test(
+) {
+  return _Test_1(
+  );
+}
+
+final _dart_Test _Test_1 = _dylib.lookupFunction<_c_Test_1,_dart_Test>('Test');
+
+typedef _c_Test_1 = ffi.Void Function(
+);
+
+typedef _dart_Test = void Function(
+);
+
+class _c_Test {
+}
+
+class init_dylib {
+}
+
+''');
+        if (file.existsSync()) {
+          file.delete();
+        }
+      } catch (e) {
+        file.writeAsStringSync(gen);
+        print('Failed test, Debug output: ${file.absolute?.path}');
+        rethrow;
+      }
+    });
   });
 }
diff --git a/test/collision_tests/decl_decl_collision_test.dart b/test/collision_tests/decl_decl_collision_test.dart
new file mode 100644
index 0000000..a96d763
--- /dev/null
+++ b/test/collision_tests/decl_decl_collision_test.dart
@@ -0,0 +1,29 @@
+// 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 'package:ffigen/src/code_generator.dart';
+import 'package:test/test.dart';
+
+void main() {
+  group('Declaration-Declaration Collision', () {
+    test('struct-func', () {
+      final l1 = Library(bindings: [
+        Func(
+          name: 'test',
+          returnType: Type.nativeType(SupportedNativeType.Void),
+        ),
+        Struc(name: 'test'),
+      ]);
+      final l2 = Library(bindings: [
+        Func(
+          name: 'test',
+          returnType: Type.nativeType(SupportedNativeType.Void),
+        ),
+        Struc(name: 'test_1'),
+      ]);
+
+      expect(l1.generate(), l2.generate());
+    });
+  });
+}
diff --git a/test/header_parser_tests/functions_test.dart b/test/header_parser_tests/functions_test.dart
index f9e261e..fa09f9c 100644
--- a/test/header_parser_tests/functions_test.dart
+++ b/test/header_parser_tests/functions_test.dart
@@ -2,47 +2,37 @@
 // 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:io';
-
 import 'package:ffigen/src/code_generator.dart';
-import 'package:ffigen/src/code_generator/writer.dart';
 import 'package:ffigen/src/header_parser.dart' as parser;
 import 'package:ffigen/src/config_provider.dart';
 import 'package:logging/logging.dart';
 import 'package:test/test.dart';
+import 'package:yaml/yaml.dart' as yaml;
+import 'package:ffigen/src/strings.dart' as strings;
 
-final writer = Writer();
+Library actual, expected;
 
 void main() {
   group('header_parser', () {
-    Library actual, expected;
-
     setUpAll(() {
       expected = expectedLibrary();
 
-      var dylibPath = 'tool/wrapped_libclang/libwrapped_clang.so';
-      if (Platform.isMacOS) {
-        dylibPath = 'tool/wrapped_libclang/libwrapped_clang.dylib';
-      } else if (Platform.isWindows) {
-        dylibPath = 'tool/wrapped_libclang/wrapped_clang.dll';
-      }
-
       Logger.root.onRecord.listen((log) {
-        print('${log.level.name.padRight(8)}: ${log.message}');
+        if (log.level > Level.INFO) {
+          print(
+              'functions_test.dart: ${log.level.name.padRight(8)}: ${log.message}');
+        }
       });
-
       actual = parser.parse(
-        Config.raw(
-          libclang_dylib_path: dylibPath,
-          headers: [
-            'test/header_parser_tests/functions.h',
-          ],
-          headerFilter: HeaderFilter(
-            includedInclusionHeaders: {
-              'functions.h',
-            },
-          ),
-        ),
+        Config.fromYaml(yaml.loadYaml('''
+${strings.output}: 'unused'
+${strings.libclang_dylib_folder}: 'tool/wrapped_libclang'
+${strings.headers}:
+  - 'test/header_parser_tests/functions.h'
+${strings.headerFilter}:
+  ${strings.include}:
+    - 'functions.h'
+        ''') as yaml.YamlMap),
       );
     });
     test('Total bindings count', () {
@@ -69,7 +59,7 @@
 String binding(Library lib, String name) {
   return lib.bindings
       .firstWhere((element) => element.name == name)
-      .toBindingString(writer)
+      .toBindingString(lib.writer)
       .string;
 }
 
@@ -78,12 +68,14 @@
     bindings: [
       Func(
         name: 'func1',
+        lookupSymbolName: 'func1',
         returnType: Type.nativeType(
           SupportedNativeType.Void,
         ),
       ),
       Func(
         name: 'func2',
+        lookupSymbolName: 'func2',
         returnType: Type.nativeType(
           SupportedNativeType.Int32,
         ),
@@ -98,6 +90,7 @@
       ),
       Func(
         name: 'func3',
+        lookupSymbolName: 'func3',
         returnType: Type.nativeType(
           SupportedNativeType.Double,
         ),
@@ -129,6 +122,7 @@
       ),
       Func(
           name: 'func4',
+          lookupSymbolName: 'func4',
           returnType: Type.pointer(Type.nativeType(SupportedNativeType.Void)),
           parameters: [
             Parameter(
diff --git a/test/prefix_tests/prefix.h b/test/prefix_tests/prefix.h
new file mode 100644
index 0000000..1e8b72d
--- /dev/null
+++ b/test/prefix_tests/prefix.h
@@ -0,0 +1,26 @@
+// 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.
+
+struct Struct1
+{
+};
+struct Test_Struct2
+{
+};
+
+void func1(struct Struct1 *s);
+void test_func2(struct Test_Struct2 *s);
+
+enum Enum1
+{
+    a = 0,
+    b = 1,
+    c = 2
+};
+enum Test_Enum2
+{
+    e = 0,
+    f = 1,
+    g = 2
+};
diff --git a/test/prefix_tests/prefix_test.dart b/test/prefix_tests/prefix_test.dart
new file mode 100644
index 0000000..d0397e4
--- /dev/null
+++ b/test/prefix_tests/prefix_test.dart
@@ -0,0 +1,150 @@
+// 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 'package:ffigen/src/code_generator.dart';
+import 'package:ffigen/src/header_parser.dart' as parser;
+import 'package:ffigen/src/config_provider.dart';
+import 'package:logging/logging.dart';
+import 'package:test/test.dart';
+import 'package:yaml/yaml.dart' as yaml;
+import 'package:ffigen/src/strings.dart' as strings;
+
+Library actual, expected;
+final functionPrefix = 'fff';
+final structPrefix = 'sss';
+final enumPrefix = 'eee';
+
+final functionPrefixReplacedWith = 'rf';
+final structPrefixReplacedWith = 'rs';
+final enumPrefixReplacedWith = 're';
+
+void main() {
+  group('Global Prefix Test', () {
+    setUpAll(() {
+      Logger.root.onRecord.listen((log) {
+        if (log.level > Level.INFO) {
+          print(
+              'prefix_test.dart: ${log.level.name.padRight(8)}: ${log.message}');
+        }
+      });
+      expected = expectedLibrary();
+      actual = parser.parse(Config.fromYaml(yaml.loadYaml('''
+${strings.output}: 'unused'
+${strings.libclang_dylib_folder}: 'tool/wrapped_libclang'
+${strings.headers}:
+  - 'test/prefix_tests/prefix.h'
+${strings.headerFilter}:
+  ${strings.include}:
+    - 'prefix.h'
+
+functions:
+  ${strings.prefix}: $functionPrefix
+  ${strings.prefix_replacement}:
+    'test_': '$functionPrefixReplacedWith'
+
+structs:
+  ${strings.prefix}: $structPrefix
+  ${strings.prefix_replacement}:
+    'Test_': '$structPrefixReplacedWith'
+
+enums:
+  ${strings.prefix}: $enumPrefix
+  ${strings.prefix_replacement}:
+    'Test_': '$enumPrefixReplacedWith'
+
+    ''') as yaml.YamlMap));
+    });
+
+    test('Function prefix', () {
+      expect(binding(actual, '${functionPrefix}func1'),
+          binding(expected, '${functionPrefix}func1'));
+    });
+    test('Struct prefix', () {
+      expect(binding(actual, '${structPrefix}Struct1'),
+          binding(expected, '${structPrefix}Struct1'));
+    });
+    test('Enum prefix', () {
+      expect(binding(actual, '${enumPrefix}Enum1'),
+          binding(expected, '${enumPrefix}Enum1'));
+    });
+    test('Function prefix-replacement', () {
+      expect(
+          binding(
+              actual, '${functionPrefix}${functionPrefixReplacedWith}func2'),
+          binding(
+              expected, '${functionPrefix}${functionPrefixReplacedWith}func2'));
+    });
+    test('Struct prefix-replacement', () {
+      expect(
+          binding(actual, '${structPrefix}${structPrefixReplacedWith}Struct2'),
+          binding(
+              expected, '${structPrefix}${structPrefixReplacedWith}Struct2'));
+    });
+    test('Enum prefix-replacement', () {
+      expect(binding(actual, '${enumPrefix}${enumPrefixReplacedWith}Enum2'),
+          binding(expected, '${enumPrefix}${enumPrefixReplacedWith}Enum2'));
+    });
+  });
+}
+
+/// Extracts a binding's string with a given name from a library.
+String binding(Library lib, String name) {
+  return lib.bindings
+      .firstWhere((element) => element.name == name)
+      .toBindingString(lib.writer)
+      .string;
+}
+
+Library expectedLibrary() {
+  final struc1 = Struc(name: '${structPrefix}Struct1');
+  final struc2 =
+      Struc(name: '${structPrefix}${structPrefixReplacedWith}Struct2');
+  return Library(
+    bindings: [
+      Func(
+        name: '${functionPrefix}func1',
+        lookupSymbolName: 'func1',
+        returnType: Type.nativeType(
+          SupportedNativeType.Void,
+        ),
+        parameters: [
+          Parameter(
+            name: 's',
+            type: Type.pointer(Type.struct(struc1)),
+          ),
+        ],
+      ),
+      Func(
+        name: '${functionPrefix}${functionPrefixReplacedWith}func2',
+        lookupSymbolName: 'test_func2',
+        returnType: Type.nativeType(
+          SupportedNativeType.Void,
+        ),
+        parameters: [
+          Parameter(
+            name: 's',
+            type: Type.pointer(Type.struct(struc2)),
+          ),
+        ],
+      ),
+      struc1,
+      struc2,
+      EnumClass(
+        name: '${enumPrefix}Enum1',
+        enumConstants: [
+          EnumConstant(name: 'a', value: 0),
+          EnumConstant(name: 'b', value: 1),
+          EnumConstant(name: 'c', value: 2),
+        ],
+      ),
+      EnumClass(
+        name: '${enumPrefix}${enumPrefixReplacedWith}Enum2',
+        enumConstants: [
+          EnumConstant(name: 'e', value: 0),
+          EnumConstant(name: 'f', value: 1),
+          EnumConstant(name: 'g', value: 2),
+        ],
+      ),
+    ],
+  );
+}