Including C++ library that uses std::optional causes linker command to fail

Hello,
We have a bit of code using Eigen that we wanted to move to a swift package so we could more easily share it internally, but I've run into a problem as the c++ code we have on top of Eigen uses std::optional.

The package seems ok, it seems to build ok, say with swift build, no errors are reported. But if I include the package in a project, or try to run tests, I get errors of the form:

Undefined symbols for architecture x86_64:
  "__ZN12optionalTest12OptionalTest16optionalVector3fEb", referenced from:
      +[ObjCOptionalTest nullableFloat3:] in ObjCOptionalTest.mm.o
ld: symbol(s) not found for architecture x86_64
[2/3] Linking SwiftyEigenPackageTests
error: fatalError

To demonstrate the problem, I made a very basic implementation with a single use of std::optional using a fork of the SwiftyEigen demo project, you can find it here.

I figured out various things already, using swift tools 5.4, setting minimum platform versions, and using cxxLanguageStandard .gnucxx17, but now I'm utterly stuck and have no clue how to proceed.

Any help greatly appreciated

Am I being a bit dumb here, is it that the cpp file is ignored?

Did you try building and testing from objective-c first?

The package structure is confusing, because Sources and Tests don't contain subdirectories named after the targets, and there isn't a target for Sources/CPP.

I think the problem is that optionalTest.cpp is outside of your ObjCEigen target. You could try adding a sources list:

     targets: [
         .target(
             name: "ObjCEigen",
             path: "Sources/ObjC",
+            sources: ["../CPP/optionalTest"],
             cxxSettings: [
                 .headerSearchPath("../CPP/eigen/"),
                 .headerSearchPath("../CPP/optionalTest"),
                 .define("EIGEN_MPL2_ONLY")
             ]
         ),

Your .gitmodules file has two submodule entries (with the same URL). Should one of these be removed?

I think I led myself down the wrong path when I was struggling to get optional to work and specifying c++17, the issue is really how to include the hpp and cpp files as I had them in the original xcode project, where of course, the project specifies the inclusion the cpp file in the target

So, the issue with optional was a total red herring.
I reorganised the folder structure a bit and added a new target.
The new target contains the cpp and hpp files that extended Eigen (hpp is in an include folder the same as for the objective c target)
The new target has the headerSearchPath point to Eigen.
The objective c target has the Eigen extension as a dependency and now everything works.
Removing the original code from my project and added the new package, all tests pass.

I cleaned it up. The fork now shows a working solution

1 Like