# Use nontrivial C++ library in Swift package

**URL:** <https://forums.swift.org/t/use-nontrivial-c-library-in-swift-package/73128>\
**Category:** Using Swift\
**Tags:** cxx-interop\
**Created:** [July 12, 2024, 8:21am UTC](https://forums.swift.org/t/use-nontrivial-c-library-in-swift-package/73128 "2024-07-12T08:21:32Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![penmanglewood](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/penmanglewood/32/30888_2.png) [@penmanglewood](https://forums.swift.org/u/penmanglewood)\
**Post date:** [July 12, 2024, 8:21am UTC](https://forums.swift.org/t/use-nontrivial-c-library-in-swift-package/73128/1 "2024-07-12T08:21:32Z")

</div>

I'd like to use the C++ library [GitHub - google/robotstxt: The repository contains Google's robots.txt parser and matcher as a C++ library (compliant to C++11).](https://github.com/google/robotstxt) in a Swift package, but I'm having trouble putting it all together.

I've reached a point where Xcode recognizes and can import `robotstxt`, but am stuck with the following build error:

> error: 'googlebot.RobotsMatcher' cannot be constructed because it has no accessible initializers

At a very high level, my approach so far has been the following:

1. Create a Swift executable package.
2. Fetch and build the external library. (One caveat here is that the main class for this library has deleted its copy constructor, making it a noncopyable type. In this case [we need to map it to a Swift reference type](https://www.swift.org/documentation/cxx-interop/#mapping-c-types-to-swift-reference-types) before building).
3. Move the library headers into Sources/robotstxt/include and the built libs into Sources/robotstxt/lib.
4. Create a modulemap for robotstxt.
5. Set up Package.swift with the library target and set the headers and linker path to the ones mentioned above.

After all this, I can `import robotstxt` in main.swift and can even see code completion for its various symbols. However, when I run `swift build`, I get the error `error: 'googlebot.RobotsMatcher' cannot be constructed because it has no accessible initializers`.

**Package.swift**

```swift
// swift-tools-version: 5.10
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "spm-with-cpp",
    targets: [
        .target(
            name: "robotstxt",
            linkerSettings: [
                .unsafeFlags(["-L./Sources/robotstxt/lib"]),
                .linkedLibrary("robots"),
            ]
        ),
        .executableTarget(
            name: "spm-with-cpp", 
            dependencies: ["robotstxt"],
            swiftSettings: [.interoperabilityMode(.Cxx)]
        ),
    ]
)

```

**Sources/robotstxt/include/module.modulemap**

```swift
module robotstxt {
    header "robots.h"
    export *
}

```

**Sources/spm-with-swift/main.swift**

```swift
// The Swift Programming Language
// https://docs.swift.org/swift-book

import robotstxt

let _ = googlebot.RobotsMatcher()
// Error: 'googlebot.RobotsMatcher' cannot be constructed because it has no accessible initializers

```

**Appendix - the specific steps i took**

```bash
# 1. Initialize the package
swift package init --type executable
mkdir Sources/spm-with-cpp
mv Sources/main.swift Sources/spm-with-cpp
mkdir External && cd External

# 2. Fetch the library
git clone https://github.com/google/robotstxt
cd robotstxt
# Edit robots.h to include `<swift/bridging>` and add `SWIFT_UNSAFE_REFERENCE` to the end of the RobotsMatcher class declaration.

# 3. Build the library
mkdir c-build && c-build
cmake .. # with cmake version 3.30.0
make

# 4. Move the headers and build artifacts to the target
cd ../../..
mkdir -p Sources/robotstxt/include/absl
mkdir Sources/robotstxt/lib
cp External/robotstxt/robots.h Sources/robotstxt/include
cp -R External/robotstxt/c-build/libs/abseil-cpp-src/absl/* Sources/robotstxt/include/absl
find Sources/robotstxt/include/absl -name '*.cc' | xargs rm
find Sources/robotstxt/include/absl -name '*.c' | xargs rm
cp External/robotstxt/c-build/librobots.a Sources/robotstxt/lib
cp External/robotstxt/c-build/librobots.dylib Sources/robotstxt/lib

```

**Appendix - actual usage of the C++ library**

Helpfully, the google library also ships with a CLI executable. Seeing [how they use the RobotsMatcher class](https://github.com/google/robotstxt/blob/master/robots_main.cc#L96-L98), it looks very straightforward.

```cpp
googlebot::RobotsMatcher matcher;
std::string url = argv[3];
bool allowed = matcher.AllowedByRobots(robots_content, &user_agents, url);

```

---

<div class="post-metadata">

**Author:** ![penmanglewood](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/penmanglewood/32/30888_2.png) [@penmanglewood](https://forums.swift.org/u/penmanglewood)\
**Post date:** [December 19, 2024, 3:46pm UTC](https://forums.swift.org/t/use-nontrivial-c-library-in-swift-package/73128/2 "2024-12-19T15:46:12Z")

</div>

It turns out the problem was that the class `googlebot.RobotsMatcher` needed to be mapped to a Swift reference type.

The class declaration deletes its copy constructor and disallows assignment:

```swift
// Disallow copying and assignment.
RobotsMatcher(const RobotsMatcher&) = delete;
RobotsMatcher& operator=(const RobotsMatcher&) = delete;

```

[Mixing Swift and C++](https://www.swift.org/documentation/cxx-interop/) says:

> C++ structures and classes with a deleted copy constructor are represented as non-copyable Swift types (`~Copyable`). If a C++ type has a valid copy constructor, it is still possible to make it non-copyable in Swift by annotating it with a `SWIFT_NONCOPYABLE` macro.
