Ошибка использования C++ в проекте Swift для Xcode: неопределенные символы для архитектуры x86_64

В Интернете есть много вопросов по этому поводу, но я не смог решить свою проблему. Я изучал это в течение нескольких дней.

Я хочу запустить простой класс C++ в проекте Swift, к этому я следовал этому руководству: http://www.swiftprogrammer.info/swift_call_cpp.html. В основном я следовал за шагами:

  1. Создайте junk.cpp а также junk.h файлы
  2. Скомпилировать используя g++ or/and clang++
  3. Создайте.a файл с: $ ar r libjunkcpp.a junk.o
  4. ranlib libjunkcpp.a
  5. Связано с Xcode в Build Phases -> Link Binary With Libraries -> Add

Когда я компилирую, возникают следующие ошибки:

Undefined symbols for architecture x86_64:
  "A::getInt()", referenced from:
      _getIntFromCPP in wrapper.o
  "A::A(int)", referenced from:
      _getIntFromCPP in wrapper.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

junk.h

class A {
    public:
    A(int);
    int getInt();

    private:
    int m_Int;
};

junk.cpp

#include "junk.h"

A::A(int _i) : m_Int(_i) {}

int A::getInt() {
    return m_Int
}

wrapper.cpp

#include "junk.h"

extern "C" int getIntFromCPP() {
    // Create an instance of A, defined in
    // the library, and call getInt() on it:
    return A(1234).getInt();
}

bridge.h

int getIntFromCPP();

1 ответ

Это проблема, которая иногда возникает при использовании библиотек C или C++, которые соединяются через Objective-C с Swift. Проблема не в том, как создается архив (статическая библиотека), а в том, что приложение создает чрезмерно агрессивный компоновщик.

Проблема в том, что компоновщик видит символы привязки и символы C++, но никогда не видит, что он вызывается из любого места, потому что на самом деле он вызывается из другого языка (Swift). В конечном итоге это приводит к тому, что компоновщик агрессивно удаляет все символы, которые, по его мнению, не используются, с целью экономии места, что эффективно удаляет весь код C++.

Когда это произойдет, nm сообщит о правильных символах как о существующих в архиве, но фактическое приложение не выполнится из-за того, что символы не найдены.


Что касается решений, на самом деле в Stack Overflow уже есть несколько вопросов / ответов, которые в разной степени решают эту проблему:

, где решение состоит в использовании флага компоновщика для принудительной загрузки статических символов.
  • Предотвращение удаления неиспользуемых символов из статической библиотеки Xcode,

  • предлагающей использовать __attribute__((constructor)) чтобы обмануть компоновщика, заставив его думать, что символы необходимы при построении, и таким образом сохранить их.
  • Ошибки полосы отладки архива Xcode

  • , которые в более широком смысле предполагают переключение некоторых конфигураций Xcode, которые могут привести к тому, что символы не будут удалены. Однако предложения в ответах здесь могут противоречить двум указанным выше ссылкам.

    Трудно дать окончательный и ясный ответ без дополнительной информации о существующей настройке, например, где wrapper.cppпостроен, и как привязки используются в проекте Swift. Учитывая, что это вопрос из 2018 года, я не подозреваю, что будет гораздо больше информации о том, что это за установка была в то время.

    Судя по описанным симптомам, это похоже на проблему, с которой столкнулись мои коллеги при связывании C++ / Swift - и в конечном итоге решение заключалось в использовании -force_load что обеспечивает полное сохранение архива в окончательном приложении.

    Другие вопросы по тегам