swiftlang / swift-package-manager

The Package Manager for the Swift Programming Language
Apache License 2.0
9.74k stars 1.35k forks source link

C++ Interop causing Swift tests to fail to build with a linker error #6998

Open CoryFoy opened 1 year ago

CoryFoy commented 1 year ago

Description

I've explained some of the issue in this forum post but tl;dr:

I have a minimal repro available here on GitHub.

Expected behavior

To be able to build the entire project.

Actual behavior

I get the following Linker Errors:

ld: Undefined symbols:
  double GeographicLib::Math::AngNormalize<double>(double), referenced from:
      GeographicLib::GeoCoords::Reset(double, double, int) in CppIssueRepro.o
  GeographicLib::UTMUPS::Forward(double, double, int&, bool&, double&, double&, double&, double&, int, bool), referenced from:
      GeographicLib::GeoCoords::Reset(double, double, int) in CppIssueRepro.o
  GeographicLib::GeoCoords::MGRSRepresentation(int) const, referenced from:
      CppIssueRepro.CoordinateCalculator.coverttoMGRS(lat: Swift.Double, lon: Swift.Double) -> Swift.String in CppIssueRepro.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Steps to reproduce

  1. I have the C++ library's .a file and the headers. I created a folder in my package for the library, drug the include folder into it, and then added the .a file at the root of the folder.
  2. I created an Umbrella header in the include folder, along with a module.
  3. I then created a shim file (per https://github.com/apple/swift-package-manager/issues/5706)
  4. Finally, I modified my package file to build the target, and reference it as a dependency

Swift Package Manager version/commit hash

5.9

Swift & OS version (output of swift --version ; uname -a)

swift-driver version: 1.87.1 Apple Swift version 5.9 (swiftlang-5.9.0.128.108 clang-1500.0.40.1)
Target: x86_64-apple-macosx13.0
Darwin Thunderball 22.6.0 Darwin Kernel Version 22.6.0: Fri Sep 15 13:39:52 PDT 2023; root:xnu-8796.141.3.700.8~1/RELEASE_X86_64 x86_64
neonichu commented 1 year ago

This seems expected to me, since SwiftPM will not link libGeographicLib.a, so the linker errors are correct.

What is surprising to me is that there is no mention of the library existing in a target directory without being handled explicitly, so that seems like a bug. I would expect a warning for that.

CoryFoy commented 1 year ago

Thanks @neonichu - I'm fairly new to linking Swift to C++ - is there an additional flag I can pass in to link them together? Or would I be better off just including the whole source instead of just the compiled library and letting it build?

And is there any reason why it's compiling fine for the main library but not for the tests?

(Come to think of it - maybe it is better for me to include the source rather than the compiled library on the off chance others need to use my library on other platforms)

neonichu commented 1 year ago

And is there any reason why it's compiling fine for the main library but not for the tests?

It only happens for the tests since that's the only "final" executable being produced which resolves all the symbols. For the library target, we are only producing object files and so no linker invocation happens.

Typically, we always recommend distributing source unless there's a strong reason for using a binary instead. For binaries, this describes how to package them for use with SwiftPM. This is currently only supported when targeting Apple platforms.

grynspan commented 2 months ago

Possibly related to #6661.