Use `package:config` WIP
diff --git a/lib/src/config_provider/config.dart b/lib/src/config_provider/config.dart
index 6290bac..369668e 100644
--- a/lib/src/config_provider/config.dart
+++ b/lib/src/config_provider/config.dart
@@ -6,6 +6,7 @@
 
 import 'dart:io';
 
+import 'package:config/config.dart' as pkg_config;
 import 'package:ffigen/src/code_generator.dart';
 import 'package:logging/logging.dart';
 import 'package:package_config/package_config_types.dart';
@@ -22,11 +23,9 @@
 /// Handles validation, extraction of confiurations from yaml file.
 class Config {
   /// Input filename.
-  String? get filename => _filename;
   String? _filename;
 
   /// Package config.
-  PackageConfig? get packageConfig => _packageConfig;
   PackageConfig? _packageConfig;
 
   /// Location for llvm/lib folder.
@@ -177,17 +176,32 @@
   /// Create config from Yaml map.
   factory Config.fromYaml(YamlMap map,
       {String? filename, PackageConfig? packageConfig}) {
+    final config = pkg_config.Config(
+      fileParsed: map.cast(),
+      fileSourceUri: Uri(path: filename),
+    );
+
+    return Config.fromConfig(
+      config,
+      filename: filename,
+      packageConfig: packageConfig,
+    );
+  }
+
+  /// Create config from Yaml map.
+  factory Config.fromConfig(pkg_config.Config config,
+      {String? filename, PackageConfig? packageConfig}) {
     final configspecs = Config._(filename, packageConfig);
-    _logger.finest('Config Map: $map');
+    _logger.finest('Config: $config');
 
     final specs = configspecs._getSpecs();
 
-    final result = configspecs._checkConfigs(map, specs);
+    final result = configspecs._checkConfigs(config, specs);
     if (!result) {
       throw FormatException('Invalid configurations provided.');
     }
 
-    configspecs._extract(map, specs);
+    configspecs._extract(config, specs);
     return configspecs;
   }
 
@@ -212,12 +226,14 @@
   }
 
   /// Validates Yaml according to given specs.
-  bool _checkConfigs(YamlMap map, Map<List<String>, Specification> specs) {
+  bool _checkConfigs(
+      pkg_config.Config config, Map<List<String>, Specification> specs) {
     var result = true;
     for (final key in specs.keys) {
       final spec = specs[key];
-      if (checkKeyInYaml(key, map)) {
-        result = result && spec!.validator(key, getKeyValueFromYaml(key, map));
+      final value = config.getFileValue<Object>(key.join('.'));
+      if (value != null) {
+        result = result && spec!.validator(key, value);
       } else if (spec!.requirement == Requirement.yes) {
         _logger.severe("Key '$key' is required.");
         result = false;
@@ -226,7 +242,10 @@
       }
     }
     // Warn about unknown keys.
-    warnUnknownKeys(specs.keys.toList(), map);
+    // warnUnknownKeys(specs.keys.toList(), map);
+    // TODO(dacoharkes): Should the config allow access to the list of keys?
+    // Should that access be uniform across env/cli/file? Environment is not
+    // going to be empty.
 
     return result;
   }
@@ -234,23 +253,22 @@
   /// Extracts variables from Yaml according to given specs.
   ///
   /// Validation must be done beforehand, using [_checkConfigs].
-  void _extract(YamlMap map, Map<List<String>, Specification> specs) {
+  void _extract(
+      pkg_config.Config config, Map<List<String>, Specification> specs) {
     for (final key in specs.keys) {
-      final spec = specs[key];
-      if (checkKeyInYaml(key, map)) {
-        spec!.extractedResult(spec.extractor(getKeyValueFromYaml(key, map)));
-      } else {
-        spec!.extractedResult(spec.defaultValue?.call());
-      }
+      final spec = specs[key]!;
+      final value = spec.extractor(config) ?? spec.defaultValue?.call();
+      spec.extractedResult(value);
     }
   }
 
-  /// Returns map of various specifications avaialble for our tool.
+  /// Returns map of various specifications available for our tool.
   ///
   /// Key: Name, Value: [Specification]
   Map<List<String>, Specification> _getSpecs() {
     return <List<String>, Specification>{
       [strings.llvmPath]: Specification<String>(
+        key: [strings.llvmPath],
         requirement: Requirement.no,
         validator: llvmPathValidator,
         extractor: llvmPathExtractor,
@@ -260,16 +278,18 @@
         },
       ),
       [strings.output]: Specification<OutputConfig>(
+        key: [strings.output],
         requirement: Requirement.yes,
         validator: outputValidator,
         extractor: (dynamic value) =>
-            outputExtractor(value, filename, packageConfig),
+            outputExtractor(value, _filename, _packageConfig),
         extractedResult: (dynamic result) {
           _output = (result as OutputConfig).output;
           _symbolFile = result.symbolFile;
         },
       ),
       [strings.language]: Specification<Language>(
+        key: [strings.language],
         requirement: Requirement.no,
         validator: languageValidator,
         extractor: languageExtractor,
@@ -277,12 +297,14 @@
         extractedResult: (dynamic result) => _language = result as Language,
       ),
       [strings.headers]: Specification<Headers>(
+        key: [strings.headers],
         requirement: Requirement.yes,
         validator: headersValidator,
-        extractor: (dynamic value) => headersExtractor(value, filename),
+        extractor: (dynamic value) => headersExtractor(value, _filename),
         extractedResult: (dynamic result) => _headers = result as Headers,
       ),
       [strings.compilerOpts]: Specification<List<String>>(
+        key: [strings.compilerOpts],
         requirement: Requirement.no,
         validator: compilerOptsValidator,
         extractor: compilerOptsExtractor,
@@ -291,6 +313,7 @@
             _compilerOpts = result as List<String>,
       ),
       [strings.compilerOptsAuto]: Specification<CompilerOptsAuto>(
+        key: [strings.compilerOptsAuto],
           requirement: Requirement.no,
           validator: compilerOptsAutoValidator,
           extractor: compilerOptsAutoExtractor,
@@ -298,8 +321,10 @@
           extractedResult: (dynamic result) {
             _compilerOpts
                 .addAll((result as CompilerOptsAuto).extractCompilerOpts());
-          }),
+        },
+      ),
       [strings.functions]: Specification<Declaration>(
+        key: [strings.functions],
         requirement: Requirement.no,
         validator: declarationConfigValidator,
         extractor: declarationConfigExtractor,
@@ -309,6 +334,7 @@
         },
       ),
       [strings.structs]: Specification<Declaration>(
+        key: [strings.structs],
         requirement: Requirement.no,
         validator: declarationConfigValidator,
         extractor: declarationConfigExtractor,
@@ -318,6 +344,7 @@
         },
       ),
       [strings.unions]: Specification<Declaration>(
+        key: [strings.unions],
         requirement: Requirement.no,
         validator: declarationConfigValidator,
         extractor: declarationConfigExtractor,
@@ -327,6 +354,7 @@
         },
       ),
       [strings.enums]: Specification<Declaration>(
+        key: [strings.enums],
         requirement: Requirement.no,
         validator: declarationConfigValidator,
         extractor: declarationConfigExtractor,
@@ -336,6 +364,7 @@
         },
       ),
       [strings.unnamedEnums]: Specification<Declaration>(
+        key: [strings.unnamedEnums],
         requirement: Requirement.no,
         validator: declarationConfigValidator,
         extractor: declarationConfigExtractor,
@@ -344,6 +373,7 @@
             _unnamedEnumConstants = result as Declaration,
       ),
       [strings.globals]: Specification<Declaration>(
+        key: [strings.globals],
         requirement: Requirement.no,
         validator: declarationConfigValidator,
         extractor: declarationConfigExtractor,
@@ -353,6 +383,7 @@
         },
       ),
       [strings.macros]: Specification<Declaration>(
+        key: [strings.macros],
         requirement: Requirement.no,
         validator: declarationConfigValidator,
         extractor: declarationConfigExtractor,
@@ -362,6 +393,7 @@
         },
       ),
       [strings.typedefs]: Specification<Declaration>(
+        key: [strings.typedefs],
         requirement: Requirement.no,
         validator: declarationConfigValidator,
         extractor: declarationConfigExtractor,
@@ -371,6 +403,7 @@
         },
       ),
       [strings.objcInterfaces]: Specification<Declaration>(
+        key: [strings.objcInterfaces],
         requirement: Requirement.no,
         validator: declarationConfigValidator,
         extractor: declarationConfigExtractor,
@@ -381,6 +414,7 @@
       ),
       [strings.objcInterfaces, strings.objcModule]:
           Specification<Map<String, String>>(
+        key: [strings.objcInterfaces, strings.objcModule],
         requirement: Requirement.no,
         validator: stringStringMapValidator,
         extractor: stringStringMapExtractor,
@@ -389,6 +423,7 @@
             ObjCModulePrefixer(result as Map<String, String>),
       ),
       [strings.libraryImports]: Specification<Map<String, LibraryImport>>(
+        key: [strings.libraryImports],
         validator: libraryImportsValidator,
         extractor: libraryImportsExtractor,
         defaultValue: () => <String, LibraryImport>{},
@@ -398,9 +433,10 @@
       ),
       [strings.import, strings.symbolFilesImport]:
           Specification<Map<String, ImportedType>>(
+        key: [strings.import, strings.symbolFilesImport],
         validator: symbolFileImportValidator,
         extractor: (value) => symbolFileImportExtractor(
-            value, _libraryImports, filename, packageConfig),
+            value, _libraryImports, _filename, _packageConfig),
         defaultValue: () => <String, ImportedType>{},
         extractedResult: (dynamic result) {
           _usrTypeMappings = result as Map<String, ImportedType>;
@@ -408,6 +444,7 @@
       ),
       [strings.typeMap, strings.typeMapTypedefs]:
           Specification<Map<String, List<String>>>(
+        key: [strings.typeMap, strings.typeMapTypedefs],
         validator: typeMapValidator,
         extractor: typeMapExtractor,
         defaultValue: () => <String, List<String>>{},
@@ -418,6 +455,7 @@
       ),
       [strings.typeMap, strings.typeMapStructs]:
           Specification<Map<String, List<String>>>(
+        key: [strings.typeMap, strings.typeMapStructs],
         validator: typeMapValidator,
         extractor: typeMapExtractor,
         defaultValue: () => <String, List<String>>{},
@@ -428,6 +466,7 @@
       ),
       [strings.typeMap, strings.typeMapUnions]:
           Specification<Map<String, List<String>>>(
+        key: [strings.typeMap, strings.typeMapUnions],
         validator: typeMapValidator,
         extractor: typeMapExtractor,
         defaultValue: () => <String, List<String>>{},
@@ -438,6 +477,7 @@
       ),
       [strings.typeMap, strings.typeMapNativeTypes]:
           Specification<Map<String, List<String>>>(
+        key: [strings.typeMap, strings.typeMapNativeTypes],
         validator: typeMapValidator,
         extractor: typeMapExtractor,
         defaultValue: () => <String, List<String>>{},
@@ -447,29 +487,36 @@
         },
       ),
       [strings.excludeAllByDefault]: Specification<bool>(
+        key: [strings.excludeAllByDefault],
         requirement: Requirement.no,
         validator: booleanValidator,
         extractor: booleanExtractor,
+        extractor2: booleanExtractor2,
         defaultValue: () => false,
         extractedResult: (dynamic result) =>
             _excludeAllByDefault = result as bool,
       ),
       [strings.sort]: Specification<bool>(
+        key: [strings.sort],
         requirement: Requirement.no,
         validator: booleanValidator,
         extractor: booleanExtractor,
+        extractor2: booleanExtractor2,
         defaultValue: () => false,
         extractedResult: (dynamic result) => _sort = result as bool,
       ),
       [strings.useSupportedTypedefs]: Specification<bool>(
+        key: [strings.useSupportedTypedefs],
         requirement: Requirement.no,
         validator: booleanValidator,
         extractor: booleanExtractor,
+        extractor2: booleanExtractor2,
         defaultValue: () => true,
         extractedResult: (dynamic result) =>
             _useSupportedTypedefs = result as bool,
       ),
       [strings.comments]: Specification<CommentType>(
+        key: [strings.comments],
         requirement: Requirement.no,
         validator: commentValidator,
         extractor: commentExtractor,
@@ -479,6 +526,7 @@
       ),
       [strings.structs, strings.dependencyOnly]:
           Specification<CompoundDependencies>(
+        key: [strings.structs, strings.dependencyOnly],
         requirement: Requirement.no,
         validator: dependencyOnlyValidator,
         extractor: dependencyOnlyExtractor,
@@ -488,6 +536,7 @@
       ),
       [strings.unions, strings.dependencyOnly]:
           Specification<CompoundDependencies>(
+        key: [strings.unions, strings.dependencyOnly],
         requirement: Requirement.no,
         validator: dependencyOnlyValidator,
         extractor: dependencyOnlyExtractor,
@@ -497,6 +546,7 @@
       ),
       [strings.structs, strings.structPack]:
           Specification<StructPackingOverride>(
+        key: [strings.structs, strings.structPack],
         requirement: Requirement.no,
         validator: structPackingOverrideValidator,
         extractor: structPackingOverrideExtractor,
@@ -505,6 +555,7 @@
             _structPackingOverride = result as StructPackingOverride,
       ),
       [strings.name]: Specification<String>(
+        key: [strings.name],
         requirement: Requirement.prefer,
         validator: dartClassNameValidator,
         extractor: stringExtractor,
@@ -512,6 +563,7 @@
         extractedResult: (dynamic result) => _wrapperName = result as String,
       ),
       [strings.description]: Specification<String?>(
+        key: [strings.description],
         requirement: Requirement.prefer,
         validator: nonEmptyStringValidator,
         extractor: stringExtractor,
@@ -520,20 +572,24 @@
             _wrapperDocComment = result as String?,
       ),
       [strings.preamble]: Specification<String?>(
+        key: [strings.preamble],
         requirement: Requirement.no,
         validator: nonEmptyStringValidator,
         extractor: stringExtractor,
         extractedResult: (dynamic result) => _preamble = result as String?,
       ),
       [strings.useDartHandle]: Specification<bool>(
+        key: [strings.useDartHandle],
         requirement: Requirement.no,
         validator: booleanValidator,
         extractor: booleanExtractor,
+        extractor2: booleanExtractor2,
         defaultValue: () => true,
         extractedResult: (dynamic result) => _useDartHandle = result as bool,
       ),
       [strings.functions, strings.exposeFunctionTypedefs]:
           Specification<Includer>(
+        key: [strings.functions, strings.exposeFunctionTypedefs],
         requirement: Requirement.no,
         validator: exposeFunctionTypeValidator,
         extractor: exposeFunctionTypeExtractor,
@@ -542,6 +598,7 @@
             _exposeFunctionTypedefs = result as Includer,
       ),
       [strings.functions, strings.leafFunctions]: Specification<Includer>(
+        key: [strings.functions, strings.leafFunctions],
         requirement: Requirement.no,
         validator: leafFunctionValidator,
         extractor: leafFunctionExtractor,
@@ -550,6 +607,7 @@
             _leafFunctions = result as Includer,
       ),
       [strings.ffiNative]: Specification<FfiNativeConfig>(
+        key: [strings.ffiNative],
         requirement: Requirement.no,
         validator: ffiNativeValidator,
         extractor: ffiNativeExtractor,
diff --git a/lib/src/config_provider/config_types.dart b/lib/src/config_provider/config_types.dart
index 8521bdb..a6b8f83 100644
--- a/lib/src/config_provider/config_types.dart
+++ b/lib/src/config_provider/config_types.dart
@@ -5,6 +5,7 @@
 /// Contains all the neccesary classes required by config.
 import 'dart:io';
 
+import 'package:config/config.dart' as pkg_config;
 import 'package:quiver/pattern.dart' as quiver;
 
 import 'path_finder.dart';
@@ -67,17 +68,21 @@
 ///
 /// [E] is the return type of the extractedResult.
 class Specification<E> {
+  final List<String> key;
   final bool Function(List<String> name, dynamic value) validator;
-  final E Function(dynamic map) extractor;
+  final E Function(pkg_config.Config config) extractor;
+  final E? Function(pkg_config.Config config, List<String> key)? extractor2;
   final E Function()? defaultValue;
 
   final Requirement requirement;
   final void Function(dynamic result) extractedResult;
 
   Specification({
+    required this.key,
     required this.extractedResult,
     required this.validator,
     required this.extractor,
+    this.extractor2,
     this.defaultValue,
     this.requirement = Requirement.no,
   });
diff --git a/lib/src/config_provider/spec_utils.dart b/lib/src/config_provider/spec_utils.dart
index 9b03ebb..426a531 100644
--- a/lib/src/config_provider/spec_utils.dart
+++ b/lib/src/config_provider/spec_utils.dart
@@ -4,6 +4,7 @@
 
 import 'dart:io';
 
+import 'package:config/config.dart' as pkg_config;
 import 'package:ffigen/src/code_generator.dart';
 import 'package:ffigen/src/code_generator/utils.dart';
 import 'package:file/local.dart';
@@ -113,6 +114,9 @@
   }
 }
 
+bool? booleanExtractor2(pkg_config.Config config, List<String> key) =>
+    config.getBool(key.join('.'));
+
 bool booleanExtractor(dynamic value) => value as bool;
 
 bool booleanValidator(List<String> name, dynamic value) =>
diff --git a/lib/src/executables/ffigen.dart b/lib/src/executables/ffigen.dart
index c37cb4f..473a815 100644
--- a/lib/src/executables/ffigen.dart
+++ b/lib/src/executables/ffigen.dart
@@ -7,6 +7,7 @@
 
 import 'package:args/args.dart';
 import 'package:cli_util/cli_logging.dart' show Ansi;
+import 'package:config/config.dart' as pkg_config;
 import 'package:ffigen/ffigen.dart';
 import 'package:logging/logging.dart';
 import 'package:package_config/package_config.dart';
@@ -75,9 +76,16 @@
 
   // Parse config from yaml.
   if (result.wasParsed(conf)) {
-    config = getConfigFromCustomYaml(result[conf] as String, packageConfig);
+    config = getConfigFromCustomYaml(
+      result[conf] as String,
+      packageConfig,
+      result['defines'] as List<String>,
+    );
   } else {
-    config = getConfigFromPubspec(packageConfig);
+    config = getConfigFromPubspec(
+      packageConfig,
+      result['defines'] as List<String>,
+    );
   }
 
   // Add compiler options from command line.
@@ -91,7 +99,10 @@
 }
 
 /// Extracts configuration from pubspec file.
-Config getConfigFromPubspec(PackageConfig? packageConfig) {
+Config getConfigFromPubspec(
+  PackageConfig? packageConfig,
+  List<String> cliDefines,
+) {
   final pubspecFile = File(pubspecName);
 
   if (!pubspecFile.existsSync()) {
@@ -110,12 +121,24 @@
     _logger.severe("Couldn't find an entry for '$configKey' in $pubspecName.");
     exit(1);
   }
-  return Config.fromYaml(bindingsConfigMap,
+
+  final config = pkg_config.Config(
+    cliDefines: cliDefines,
+    environment: Platform.environment,
+    fileParsed: bindingsConfigMap.cast(),
+    fileSourceUri: pubspecFile.uri,
+  );
+
+  return Config.fromConfig(config,
       filename: pubspecFile.path, packageConfig: packageConfig);
 }
 
 /// Extracts configuration from a custom yaml file.
-Config getConfigFromCustomYaml(String yamlPath, PackageConfig? packageConfig) {
+Config getConfigFromCustomYaml(
+  String yamlPath,
+  PackageConfig? packageConfig,
+  List<String> cliDefines,
+) {
   final yamlFile = File(yamlPath);
 
   if (!yamlFile.existsSync()) {
@@ -123,7 +146,14 @@
     exit(1);
   }
 
-  return Config.fromFile(yamlFile, packageConfig: packageConfig);
+  final config = pkg_config.Config(
+    cliDefines: cliDefines,
+    environment: Platform.environment,
+    fileContents: yamlFile.readAsStringSync(),
+    fileSourceUri: yamlFile.uri,
+  );
+
+  return Config.fromConfig(config, packageConfig: packageConfig);
 }
 
 /// Parses the cmd line arguments.
@@ -158,6 +188,15 @@
     compilerOpts,
     help: 'Compiler options for clang. (E.g --$compilerOpts "-I/headers -W")',
   );
+  parser.addMultiOption(
+    'define',
+    abbr: 'D',
+    help: '''Define or override a config property from command line.
+The same option can be passed multiple times.
+Keys should only contain lower-case alphanumeric characters, underscores,
+and '.'s''',
+  );
+
 
   ArgResults results;
   try {
diff --git a/pubspec.yaml b/pubspec.yaml
index 96c6027..3f31570 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -2,6 +2,9 @@
 # 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.
 
+# DO NOT MERGE: prototype.
+publish_to: none
+
 name: ffigen
 version: 7.2.7
 description: Generator for FFI bindings, using LibClang to parse C header files.
@@ -22,6 +25,10 @@
   file: ^6.0.0
   package_config: ^2.1.0
   yaml_edit: ^2.0.3
+  config:
+    git:
+      url: https://github.com/dcharkes/config.git
+      ref: c9a6a3fb1050e2429289f0a98d5b5f97d5b988da
 
 dev_dependencies:
   lints: ^2.0.1