Integrating ​​C++ Libraries with Swift — How Speculid Is Built
Tags: swift, xcode, objectivec, cpp
Published: 2019-01-21 17:28:04

---
title: Integrating ​​C++ Libraries with Swift — How Speculid Is Built
published: true
description: Previously, I discussed using Objective-C to integrate C++ with Swift in Speculid. Today, I'm going to talk about the challenges of using C++ in Xcode.
tags: swift, xcode, objective-c, cpp
cover_image: https://thepracticaldev.s3.amazonaws.com/i/8x1ib457uypsrpzqpxfw.png
canonical_url: https://learningswift.brightdigit.com/integrating-c-plus-plus-swift/
---
In the article Objective-C and Swift — Being Friendly, I talked about how I used Objective-C to integrate C++ libraries with Swift in Speculid. Today, I’m going to talk about the challenges of using C++ Libraries in your XCode project.

[Speculid is a completely open source application](https://speculid.com/) built with the latest version of Xcode (10.1) primarily in Swift (I’ll explain why primarily and not only). With Speculid, you **can take a single graphic and build it into a complete App Icon or Image Set.**

Therefore, this meant packaging any required dependencies within the .App package. At first, I thought about including *Inkscape* and *ImageMagick* with the installation. However,​ the fact that *Inkscape* has other dependencies such as *XQuartz* meant that would be too cumbersome. Therefore, Cairo and librsvg became the obvious choice.

![](https://cdn-images-1.medium.com/max/1600/0*BUm2rlz-zf_vxX00)

![](https://cdn-images-1.medium.com/max/1600/0*_lxsCXDxYOTkGZIN)

## Integrating Cairo and librsvg with Swift

The first version of Speculid required the installation of two software packages: [Inkscape](https://inkscape.org/) and
[ImageMagick](https://www.imagemagick.org/). Each application would be used in some combination to read, manipulate, and export SVG, PNG, JPEG, or PDF files.
As a result, **requiring these software packages made the user experience clumsy and difficult.** However, since they are complete applications including both of these packages would be cumbersome as well. That’s why I looked into integrating C++ libraries — specifically two of them: [Cairo](https://cairographics.org/)**
and **[libRSVG](https://developer.gnome.org/rsvg/)**.**

Used by several software packages, **Cairo** and **librsvg** are the leading libraries for the development of graphics and SVG manipulation software especially in the open source and Linux communities. **So with Speculid v2.0, I integrated and packaged these libraries as the primary means of reading PNG and SVG and exporting PDF and PNG files**. Above all, both of these libraries can be installed on your Mac through [HomeBrew](http://brew.sh/), using the command:

`brew install cairo librsvg`

Now we’ll need to make sure to copy and link the files.

## Properly Linking and Copying C++ Libraries

In order to use C++ libraries, **we can either compile every piece of C++ code as their individual libraries within Speculid or integrate the already compiled libraries.** At first it seemed compiling the code would be the most clean and efficient way, except for the fact that each library had many requirements as well as special flags for compiling each library. Therefore I decided to take a different route and use the compiled libraries themselves.

After installing the libraries using HomeBrew, copy the directories for Cairo and librsvg to your project folder. **HomeBrew stores its applications and libraries at:**


Therefore, **Cairo**, for instance, would be located at:


Once it’s copied to your project, there are three spots the files need to be under **build phases:**

* **Link With Libraries — **all **.dylib** files need to be listed
* **Copy Files — **all **.dylib** files need to be copied to the **Frameworks**
folder
* **Headers **— all **.h** files need to be listed under **Project**

**After that, you should be good to go.** If you have any issues with building the application, **double check all the proper files are listed under build phases in your Xcode projec**t.

## Staying Organized in Dependency Hell

With your C++ libraries linked and embedded, you run the app and it works without a hitch. So then you archive and package your product and send it off for someone to run and they get something like this:


**Unfortunatley libraries like Cairo and librsvg, often have dependencies of their own which are required.** However there are a few commands to help with this:

* `otool -L` <br> If we want to find out actual dependencies, this command displays names and version numbers of libraries which are required and used by a particular library.
* `brew deps —tree`<br> In order to make sure we have all the dependencies installed on the developer machine, we can use HomeBrew to find their dependencies installed along with the package. Once they are installed we can add them to our project and include them in the App package
* `install_name_tool`<br> Once the dependencies are copied and included with our App, we need to update the paths used to look for our dependencies.

### Gathering Dependencies

Firstly we need to make sure we’ve included all the dependencies in your App by adding the dynamic libraries described by `otool -L`. For instance if we ran
`otool -L` on the Cairo library we get this:


Therefore, we see Cairo requires a few libraries like *pixman*. Thankfully, **we can get the HomeBrew dependency tree by using the command **<br> `brew deps
—tree`:


Thankfully now, if we are missing *pixman* on our development machine, we can install it using `brew install pixman` and then copy the HomeBrew cellar directory for *pixman* to our project folder.

Again make sure the dynamic libraries are part of the build process under build phases. In other words, you should have something like this under **Build Phases**:

### Updating References with `install_name_tool`

Now that all the required dependencies are included with the applications, we need to tell Speculid where to look for dependenciesndencies where to look for it’s respective dependencies. That’s where `install_name_tool` comes in.

#### Writing a Script to Search and Update Dynamic Libraries

So for this process we are going to write a script to update our dependencies,
it will need to do the following:

1.  Look for the dependencies using `otool -L` which are not system installed 1.  Update the *id* of each dynamic library and the path to use @rpath which is the run-time search path the application uses.
1.  Go through each file in our `Frameworks` folder and…
1.  Again update the *id* as well as the path to use `@rpath`
1.  Use `otool -L` to look for each dependency of that dependency 1.  And update the search path to use `@rpath`

Here is the result:


Let’s break this down…

#### Breaking Down Updating Dynamic Libraries


1.  Look for the dependencies using `otool -L` which are not system installed<br> $1 is the path to the executable or `${TARGET_BUILD_DIR}/${EXECUTABLE_PATH}`.
`otool -L` will list all the dependencies. Piping to grep, we can filter results which are not system installed but in locations like `/usr/local/opt` are installed via HomeBrew. `awk -F' ' '{ print $1 }'` will print the results into a format we can use in a for loop.


2. Update the *id* of each dynamic library and the path to use @rpath which is the run-time search path the application uses.<br> Here we go through each dependency and update the identification name and the path to look for the dependency in our framework to use `@rpath`.


3. Go through each file in our `Frameworks` folder and…


4. Again update the *id* as well as the path to use `@rpath`


5. Use `otool -L` to look for each dependency of that dependency <br> Calculate the path to the dependency and run `otool -L` to get its dependencies.


6. And update the search path to use `@rpath`

Now the application and framework should contain all that’s needed for our application to run on another machine.

*The latest version of the script can be found
*[here](https://gist.github.com/leogdion/88516f580108075c8b2d05ab7f895fd0)*.*

## Conclusion

Last time we learned [how to optimize Objective-C and Swift code so they work well together](https://learningswift.brightdigit.com/objective-c-and-swift-being-friendly/).
Today we learned how to:

* integrate C++ libraries from HomeBrew into our project
* verify all dependencies are included
* fix references using install_name_tool and a script

So with Speculid, the Swift code which run the main interface can talk to the Objective-C which interfaces with the C++ libraries. No need for external applications or cumbersome installations.

If interested check out [the presentation I did at Ann Arbor Cocoaheads on this very topic](https://www.youtube.com/watch?v=SxW5fs7_o18):

{% youtube SxW5fs7_o18 %}

What are some challenges you face using C++ Libraries? Have you ever using any libraries for an iOS app? Let me know in the comments.