Saturday, January 7, 2017

Creating a Swift module

When we develop applications with Swift, for the Linux platform, we are able to use the Swift package manager to assist us with building our application.  The package manager is integrated with the build system to automate the process of downloading, compiling and linking the dependencies for our project.

One of the ways that we can define a dependency is to create a module.  Swift organises code into modules and each module uses access controls to determine which parts of its code can be accessed outside of the module.
For several projects in this blog we will be using modules to link external C libraries to our project.   We will refer to this post when we need to create these modules. 

To create a module we need to start off my creating a separate directory for it.  If we were creating a module to link the ifaddrs.h header file to our project we would want to create the directory like this:
    
    mkdir ifaddrs

Within this directory we need to create two files:  module.modulemap and Package.swift.  The module.modulemap file will contain a list of requirements for our module while the Package.swift file defines the name of our module.  Let’s begin by looking at the Package.swift file first.  To define the Ifaddrs module we would create a Package.swift file with the following code:

    import PackageDescription
    let package = Package(
        name: "Ifaddrs"
    )

Now we need to define the requirements for the Ifaddrs module in the module.modulemap file.  For this module we simply want to import the ifaddrs.h header file therefore we would put the following code in the this file:

    module Ifaddrs [system] {
        header "/usr/include/ifaddrs.h"
        export *
    }

The Swift package manager is based on the git repository therefore before we can use this module within any project, we need to create a git repository for it.  We could put this module in a github repository but that may be too much for a simple module like this.  We can create a local repository using the following commands within the modules directory:

    git init
    git add .
    git commit –m “Initial Commit”
    git tag 0.1.0

These four commands will create a local git repository for our module with a major version number of 0 and a minor version number of 1.

In the Ifaddrs module we simply included the ifaddrs.h header file in our project but if we wanted to include a third-party library, such as the libpcap library, we would need to link the library to our project as well.  For this we could link the library as shown in the following example:

    module Cpcap [system] {
        header "/usr/include/pcap.h"
        link "pcap"
        export *
    }

Once we create a module we can use the Swift package manager to automatically import and build the module when we build our project.  To do this, all we need to do is to define a dependency on the module within the projects Package.swift file.  The following example shows how we could define a dependency on the Ifaddrs module:

     import PackageDescription

     let package = Package(
        name: "ipaddr",
        dependencies: [
            .Package(url: "../ifaddrs", majorVersion: 0, minor: 1)
        ]
    )   

The dependencies array in the package defines the list of dependencies for our project.  The url is an absolute path to our module.  In this example the module is located on our local drive however we can also define modules that should be downloaded from the internet.  The following example shows how we defined the dependency for IBM’s BlueSocket module:

    import PackageDescription

    let package = Package(
       name: "echoServer",
       dependencies: [
           .Package(url: "https://github.com/IBM-Swift/BlueSocket", majorVersion: 0, minor: 12)
       ]
    )

In this example you will notice that the url defines a github repository rather than a local repository.
Once we define the dependency for a module we need to import it in our code.  We would do this by using the import command to import the namespace define by the module. 

In the beginning of this post we created the Ifaddrs module with the following Package.swift file:
    
    import PackageDescription

    let package = Package(
        name: "Ifaddrs"
    )

This example created a namespace of Ifaddrs for the module therefore to use the functionality provided by the module in our code we need to import the namespace like this:

    import Ifaddrs

We will be using modules extensively in this blog and will refer to this post to show how to create them. 


No comments:

Post a Comment