How to use a C++ library that uses another C++ library in Swift?

Hello everyone,
I'm trying to use OpenCV in Swift, and I wrote some code to test OpenCV functionality. It works when I built it manually through clang, but don't work when I use "swift build" function. Can anyone explain what I'm doing wrong?

  1. File tree
  2. Error Message
    error: link command failed with exit code 1 (use -v to see invocation)
Sources/cxxFrontend/qualy_image.cpp:5: error: undefined reference to 'cv::FileStorage::FileStorage(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
Sources/cxxFrontend/qualy_image.cpp:7: error: undefined reference to 'cv::FileStorage::operator[](char const*) const'
Sources/cxxFrontend/qualy_image.cpp:7: error: undefined reference to 'cv::FileNode::operator[](char const*) const'
Sources/cxxFrontend/qualy_image.cpp:7: error: undefined reference to 'cv::FileNode::operator int() const'
Sources/cxxFrontend/qualy_image.cpp:10: error: undefined reference to 'cv::FileStorage::release()'
Sources/cxxFrontend/qualy_image.cpp:11: error: undefined reference to 'cv::FileStorage::~FileStorage()'
Sources/cxxFrontend/qualy_image.cpp:11: error: undefined reference to 'cv::FileStorage::~FileStorage()'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
  1. Package.swift
let package = Package(
    name: "CT_Race_Results",
    dependencies: [
        .package(url: "https://github.com/swiftcsv/SwiftCSV.git", from: "0.10.0")
    ],
    targets: [
        // Targets are the basic building blocks of a package, defining a module or a test suite.
        // Targets can depend on other targets in this package and products from dependencies.
        .target(
            name: "cxxFrontend",
        ),
        .executableTarget(
            name: "SwiftBackend",
            dependencies: ["SwiftCSV", "cxxFrontend"],
            swiftSettings: [.interoperabilityMode(.Cxx)]
        ),
    ]
)
  1. CMakeLists.txt
cmake_minimum_required(VERSION 3.5)
project( cxxFrontend )
find_package( opencv4 REQUIRED )
include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/include )
set(SOURCES qualy_image.cpp include/main_header.h )
add_executable( cxxFrontend ${SOURCES} )
target_link_libraries( cxxFrontend ${OpenCV_LIBS} )
  1. qualy_image.cpp
#include <iostream>
#include <opencv2/core.hpp>

void qualy_image() {
    cv::FileStorage fs("../Temp/qualy.json", cv::FileStorage::READ);

    int test = (int)fs["Test"]["position"];

    std::cout << test << std::endl;
    fs.release();
}

int main() {
    qualy_image();
    return 1;
}
  1. main_header.h
#include <iostream>
#include <opencv2/core.hpp>

void qualy_image();

1 Like

Hey,

So I haven't worked with any mixed CMake and SwiftPackageManager projects myself, but
I have C project that does a similar thing to what you're looking for but with LIBPNG that's pure SPM.

Also my ultimate target is a Library not a CLI.

It's pretty common for system libraries to be wrapped in a "shim" project. That might be a phrase to add to your search terms.

Do you need the C++ to also output an executable or is that just how you thought it had to be done?

Example:

ETA - Should add if you need the CMakeLists.txt file to stay for other projects you can add it to the exclude section

1 Like

Do you need the C++ to also output an executable or is that just how you thought it had to be done?

I thought that is how it should be. Is CMakeLists.txt not mandatory?


After another hour, I fixed the error by adding linkedlibrary into a C++ package settings.

            linkerSettings: [
                .linkedLibrary("opencv_core")
            ]

Although it didn't help me directly, your answer did point me to the right direction, so: thank you so much for the help. :)

1 Like

I think the linked library is more modern! Thank you for the reminder to update my example!

ETA: I only use CMake files in CMake projects, so not mandatory in a SPM build.

1 Like