Dart FFI and CLI App
Tags: flutter, dart, computerscience, productivity
Published: 2020-11-21 15:11:50

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Pre-Requisite: Install package <a href="https://pub.dev/packages/ffi" rel="noreferrer noopener" target="_blank">FFI</a> and <a href="https://pub.dev/packages/args" rel="noreferrer noopener" target="_blank">Args</a></p></blockquote>
<!-- /wp:quote -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Hosted URL&nbsp;: <a href="https://web.flatteredwithflutter.com/#/" rel="noreferrer noopener" target="_blank">https://web.flatteredwithflutter.com/#/</a></p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>We will cover briefly about</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>Using Dart FFI</li><li>Fetch login history of a user (<strong>macOS</strong>)</li><li>Create a CLI App</li></ol>
<!-- /wp:list -->

{% youtube jKbwhutlw6A %}

####Article here: https://flatteredwithflutter.com/dart-ffi-cli-dart2native/

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Note: We won’t be explaining in-depth about Dart FFI as there are good articles dedicated to it.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:list {"ordered":true} -->
<ol><li><strong>Using Dart FFI</strong></li></ol>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>FFI: (<strong>Foreign Function Interface</strong>) can be used to call the C/C++ language-based APIs</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*74SRJfqhCdzK7sFnO_zElw.png" alt="Dart FFI and CLI App"/><figcaption>Dart FFI and CLI App</figcaption></figure>
<!-- /wp:image -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:paragraph -->
<p>A statically linked library is embedded into the app’s executable image and is loaded when the app starts.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Symbols from a statically linked library can be loaded using <code>DynamicLibrary.executable</code> or <code>DynamicLibrary.process</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>A dynamically linked library is distributed in a separate file or folder within the app and loaded on-demand. A dynamically linked library can be loaded into Dart via <code>DynamicLibrary.open</code>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>How will we approach?</strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>For this article, we will be utilizing the <strong>dynamic system library.</strong>&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>In case you want to create your own dynamic library, <a href="https://flutter.dev/docs/development/platform-integration/c-interop" rel="noreferrer noopener" target="_blank">read this.</a></p></blockquote>
<!-- /wp:quote -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:heading {"level":4} -->
<h4>2. Fetch login history of a user&nbsp;(<strong>macOS</strong>)</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>Open the terminal and type this command</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">last login `username`
where username is before @ [username@Macbook-Pro]</pre>
<!-- /wp:preformatted -->

<!-- wp:list -->
<ul><li>You should get your login history. Our goal is to call this command from Dart.</li><li>This command is defined in a system dynamic library, present in the macOS.</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>In macOS, the system libraries are present in</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">/usr/lib/libSystem.dylib</pre>
<!-- /wp:preformatted -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>For getting paths for different OS, visit <a href="https://www.internalpointers.com/post/c-c-standard-library" rel="noreferrer noopener" target="_blank">here</a>.</p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>We will load our dynamic library, specified at the path above, in Dart.</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*uAm6AeQwlvDuXe0lrJE-qg.png" alt=""/><figcaption>Dart FFI and CLI&nbsp;App</figcaption></figure>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>Import the dart ffi package(present inside Flutter) as</li></ul>
<!-- /wp:list -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">import 'dart:ffi' as ffi</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>This has a class <strong>DynamicLibrary. </strong>We call the method <strong>open </strong>and load our dynamic library (<strong>Dylibs.systemDyLib</strong>).</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">class Dylibs {
  static const String systemDyLib = '/usr/lib/libSystem.dylib';
  static const String systemSymbolName = 'system';
}</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>Each dynamic library is composed of symbols. For finding the symbols in a library <a href="https://stackoverflow.com/questions/4506121/how-to-print-a-list-of-symbols-exported-from-a-dynamic-library" rel="noreferrer noopener" target="_blank">refer here</a>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now, getting the user login history falls under the symbol  <a href="https://www.mkssoftware.com/docs/man3/system.3.asp" rel="noreferrer noopener" target="_blank"><strong>System</strong></a>.</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*WNXt8o2QP7gM60fgbf6siA.png" alt=""/><figcaption>Dart FFI and CLI&nbsp;App</figcaption></figure>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>Lookup for the symbol from the loaded dynamic library using <strong>lookupFunction.</strong></li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>We have specified <strong>SystemC</strong> and <strong>SystemDart</strong> functions, which basically are</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">// C header typedef:
typedef SystemC = ffi.Void Function(ffi.Pointer&lt;Utf8> command);

// Dart header typedef
typedef SystemDart = void Function(ffi.Pointer&lt;Utf8> command);</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>This combines the lookup function and casts to a Dart function.</p>
<!-- /wp:paragraph -->

<!-- wp:list -->
<ul><li>Next, we convert the command (our last login command) into something which C understands using</li></ul>
<!-- /wp:list -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">/// Convert a [String] to a Utf8-encoded null-terminated C string.
/// Returns a malloc-allocated pointer to the result.
final cmd = Utf8.toUtf8(command);</pre>
<!-- /wp:preformatted -->

<!-- wp:list -->
<ul><li>Run the command using <code>sysFunc(cmd)</code>&nbsp;</li><li>Finally, free up the memory, since C/C++ don’t have garbage collection</li></ul>
<!-- /wp:list -->

<!-- wp:heading {"level":4} -->
<h4><strong>Create a CLI&nbsp;App</strong></h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>We will create our own command, which would have info and description regarding the CLI App.</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*4-iidNFCxWooxy7Ze01V_A.png" alt=""/><figcaption>Dart FFI and CLI&nbsp;App</figcaption></figure>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>Create our command</li></ul>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>We use the <a href="https://pub.dev/documentation/args/latest/command_runner/CommandRunner-class.html" rel="noreferrer noopener" target="_blank"><strong>CommandRunner</strong></a><strong>, </strong>and define our command(<strong>last_login</strong>) with some description as&nbsp;</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*gsFft8ZtrtZKfDTNW7xPog.png" alt=""/><figcaption>CommandRunner in&nbsp;CLI</figcaption></figure>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>Add our last login Command. In order to create your own commands, you need to extend <a href="https://pub.dev/documentation/args/latest/command_runner/Command-class.html" rel="noreferrer noopener" target="_blank"><strong>Command Class</strong></a></li></ul>
<!-- /wp:list -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">// THIS ADDS OUR LAST LOGIN COMMAND<br>runner.addCommand(LastLoginCmd());</pre>
<!-- /wp:preformatted -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Note: LastLoginCmd is our custom class</p></blockquote>
<!-- /wp:quote -->

<!-- wp:paragraph -->
<p>WE create an <strong>abstract base command</strong> class and declare the methods.</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">abstract class BaseCLICommand extends Command&lt;dynamic> {
  String loadingMessage;
  void execCommand(String arg);

  @override
  Future&lt;void> run() async {
    if (argResults.arguments.isEmpty) {
      throw Exception('😳😳 Please specify the argument');
    }

    final arg = argResults.arguments.first;
    final loadingMsg = '$loadingMessage $arg';
    stdout.write('$loadingMsg\n');
    execCommand(arg);
  }
}</pre>
<!-- /wp:preformatted -->

<!-- wp:list -->
<ul><li><strong>argResults.arguments</strong> help us in fetching the user input.</li><li><strong>stdout.write</strong> is used to print out to the console.</li><li><strong>execCommand</strong> is the function, which the extended class defines.</li></ul>
<!-- /wp:list -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:paragraph -->
<p>Our <strong>LastLoginCmd</strong> extends the above class and implements the methods.</p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*OnkQ08olSzVKaTEjBTOmoQ.png" alt=""/><figcaption>LastLoginCmd</figcaption></figure>
<!-- /wp:image -->

<!-- wp:list -->
<ul><li>After we add the command as above</li></ul>
<!-- /wp:list -->

<!-- wp:separator -->
<hr class="wp-block-separator"/>
<!-- /wp:separator -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">// THIS ADDS OUR LAST LOGIN COMMAND<br>runner.addCommand(LastLoginCmd());</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p>Finally, we run this command as</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">runner.run(args);</pre>
<!-- /wp:preformatted -->

<!-- wp:heading {"level":4} -->
<h4>Last Step (Convert to CLI&nbsp;App)</h4>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>We utilize the power of</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><code><strong>dart2native</strong></code>, which has the ability to compile Dart programs to self-contained executables. With dart2native, you can create tools for the command line on <strong>macOS, Windows, or Linux</strong> using Dart.</p>
<!-- /wp:paragraph -->

<!-- wp:list {"ordered":true} -->
<ol><li>Navigate to the directory containing your dart entry point. For instance</li></ol>
<!-- /wp:list -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*MUe3X9P9BC2F_lPtJOuTAg.png" alt=""/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p><em>My directory will be </em><strong><em>lib/ffi</em></strong></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>2. Run the command</p>
<!-- /wp:paragraph -->

<!-- wp:preformatted -->
<pre class="wp-block-preformatted">dart2native cmd_line.dart -o login_history</pre>
<!-- /wp:preformatted -->

<!-- wp:paragraph -->
<p><code>-o &lt;path&gt;</code> or <code>--output=&lt;path&gt;</code>Generates the output.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>This creates our CLI App named <strong>login_history</strong>.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Final Output</strong></p>
<!-- /wp:paragraph -->

<!-- wp:image -->
<figure class="wp-block-image"><img src="https://cdn-images-1.medium.com/max/1600/1*7m5v-d6BZ2aCYUk-jfwHKQ.png" alt=""/></figure>
<!-- /wp:image -->

*In case it helped :)*
<a href="https://www.buymeacoffee.com/aseemwangoo" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Pass Me A Coffee!!" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>

{% youtube jKbwhutlw6A %}

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p><a href="https://github.com/AseemWangoo/Experiments_with_Desktop" rel="noreferrer noopener" target="_blank">Source code for Flutter Desktop App..</a></p></blockquote>
<!-- /wp:quote -->

<!-- wp:quote -->
<blockquote class="wp-block-quote"><p>Hosted URL&nbsp;: <a href="https://web.flatteredwithflutter.com/#/" rel="noreferrer noopener" target="_blank">https://web.flatteredwithflutter.com/#/</a></p></blockquote>
<!-- /wp:quote -->