I just finished implementing the C target support in swift package manager which means it is possible to have swift package with C language targets mixed in it (previously only system modules were supported).
To checkout the new functionality lets create two packages:
Factorial
This will be a C only swiftpm package and will act as an external dependency to the second package. Create a directory named Factorial
with following structure:
├── Package.swift
└── Sources
├── Factorial.c
└── include
└── Factorial.h
Factorial.h
:
long factorial(int n);
Factorial.c
:
#include "include/Factorial.h"
long factorial(int n) {
if (n == 0 || n == 1) return 1;
return n * factorial(n-1);
}
We don’t need a modulemap because it will be automatically generated if the include
directory structure is supported. These are the supported include
structures: (foo
is the name of the module)
1. Look for include/foo/foo.h, if so, use umbrella header and error if there are any other dirs or headers outside of there
2. Look for include/foo.h, if so, use umbrella header and error if there are any other dirs outside of there
3. All other cases, umbrella the include dir
If you have a specialized need you can provide a custom modulemap inside include
directory.
Finally, place the package under git:
$ git add . && git commit -m "Initial Commit" && git tag 1.0.0
Thats it, first package is ready.
FactorialRunner
This package will contain 3 targets :
- LocalFactorial : This will be a C target which will use the external
Factorial
package we just created. - CFactorialRunner : This will be a exectuable C target which will use
LocalFactorial
to find factorial of 5. - SwiftFactorialRunner : This will be a exectuable swift target which will use
LocalFactorial
to find factorial of 5.
Ofcourse CFactorialRunner
and SwiftFactorialRunner
can directly use the external Factorial
package but we want to keep things interesting.
Structure of the package:
├── Package.swift
└── Sources
├── CFactorialRunner
│ └── main.c
├── LocalFactorial
│ ├── include
│ │ └── LocalFactorial
│ │ └── LocalFactorial.h
│ └── LocalFactorial.c
└── SwiftFactorialRunner
└── main.swift
Just to cover all cases, I placed that Localfactorial.h
is at include/Localfactorial/Localfactorial.h
instead of include/Localfactorial.h
which is one of the supported convention.
Package.swift
:
import PackageDescription
let package = Package(
name: "FactorialRunner",
targets: [
Target(name: "CFactorialRunner", dependencies: ["LocalFactorial"]),
Target(name: "SwiftFactorialRunner", dependencies: ["LocalFactorial"]),
Target(name: "LocalFactorial"),
],
dependencies: [
.Package(url: "../Factorial", majorVersion: 1),
]
)
We want to use LocalFactorial
in the exectuables so it is a dependency to CFactorialRunner
and SwiftFactorialRunner
targets.
LocalFactorial.h
:
long local_factorial(int n);
LocalFactorial.c
:
#include "include/LocalFactorial/LocalFactorial.h"
#include <Factorial.h>
long local_factorial(int n) {
return factorial(n);
}
We just use the original factorial
method and wrap it with the method local_factorial
. Since Factorial
is an external dependency it is included using angular brackets <>
and not using quotes ""
. Again we don’t need modulemap because it’ll be generated for us.
main.c
:
#include "Localfactorial/Localfactorial.h"
#include <Factorial.h>
#include <stdio.h>
int main() {
printf("%ld\n", local_factorial(5));
printf("%ld\n", factorial(5));
}
For C executable we just include the LocalFactorial
or Factorial
headers and call their methods.
main.swift
:
import LocalFactorial
import Factorial
print("\(local_factorial(5))")
print("\(factorial(5))")
For Swift executable we import the packages and done~
$ swift build
Cloning /Users/aciid/mycode/swiftpmProjects/Factorial
Resolved version: 1.0.0
mkdir -p /Users/aciid/mycode/swiftpmProjects/FactorialRunner/.build/debug/CFactorialRunner.build
mkdir -p /Users/aciid/mycode/swiftpmProjects/FactorialRunner/.build/debug/Factorial.build
mkdir -p /Users/aciid/mycode/swiftpmProjects/FactorialRunner/.build/debug/LocalFactorial.build
Compiling Factorial factorial.c
Linking Factorial
Compiling LocalFactorial localfactorial.c
Linking LocalFactorial
Compiling Swift Module 'SwiftFactorialRunner' (1 sources)
Compiling CFactorialRunner main.c
Linking CFactorialRunner
Linking .build/debug/SwiftFactorialRunner
$ .build/debug/SwiftFactorialRunner
120
120
$ .build/debug/CFactorialRunner
120
120
PS : If you work in a company with iOS development, I am looking for a new job.