Запуск функций C ++ (с STL) в приложении C - PullRequest
0 голосов
/ 02 ноября 2018

Я создаю библиотеку C ++ с экспортированными функциями C, которые используют некоторые функции STL. Я хочу включить эту библиотеку в C-приложение.

Я максимально уменьшил проблему до следующих 4 файлов.

main.c

#include "aaa.h"
#include <stdio.h>

int main()
{
    printf("Version: %u.%u\n", GetAPIMajorVersion(), GetAPIMinorVersion());
    return 0;
}

aaa.h

#ifndef AAA_H
#define AAA_H

#ifdef __cplusplus
#define DllExport extern "C"
#else // __cplusplus
#define DllExport
#endif // __cplusplus

#include <stdint.h>

DllExport uint32_t GetAPIMajorVersion();
DllExport uint32_t GetAPIMinorVersion();

#endif // AAA_H

aaa.cpp

#include "aaa.h"
#include <string>
#include <vector>

// Builds and works fine.
uint32_t GetAPIMajorVersion()
{
    std::string val = "hello world";
    return val.size();
}

// Produces the error messages
uint32_t GetAPIMinorVersion()
{
    std::vector<bool> test;
    test.push_back(true);

    return test.size();
}

Я использую следующий скрипт для сборки библиотеки и приложения.

build.sh

# Build the C++ library 
g++ -m64 -Wall -O3 -c -fmessage-length=0 -fPIC -MMD -MP aaa.cpp -o aaa.o 
ar rcs libaaa.a aaa.o 

# Build the executable 
gcc -m64 -Wall -static main.c -o main -L./ -laaa 

Я получаю следующие ошибки при попытке создать приложение C

.//libaaa.a(aaa.o): In function `GetAPIMinorVersion':
aaa.cpp:(.text+0xeb): undefined reference to `operator delete(void*)'
aaa.cpp:(.text+0x1c7): undefined reference to `operator delete(void*)'
.//libaaa.a(aaa.o): In function `std::vector<bool, std::allocator<bool> >::_M_insert_aux(std::_Bit_iterator, bool)':
aaa.cpp:(.text._ZNSt6vectorIbSaIbEE13_M_insert_auxESt13_Bit_iteratorb[_ZNSt6vectorIbSaIbEE13_M_insert_auxESt13_Bit_iteratorb]+0x1d8): undefined reference to `operator new(unsigned long)'aaa.cpp:(.text._ZNSt6vectorIbSaIbEE13_M_insert_auxESt13_Bit_iteratorb[_ZNSt6vectorIbSaIbEE13_M_insert_auxESt13_Bit_iteratorb]+0x339): undefined reference to `operator delete(void*)'
aaa.cpp:(.text._ZNSt6vectorIbSaIbEE13_M_insert_auxESt13_Bit_iteratorb[_ZNSt6vectorIbSaIbEE13_M_insert_auxESt13_Bit_iteratorb]+0x3cb): undefined reference to `std::__throw_length_error(char const*)'.//libaaa.a(aaa.o):(.data.DW.ref.__gxx_personality_v0[DW.ref.__gxx_personality_v0]+0x0): undefined reference to `__gxx_personality_v0'
collect2: error: ld returned 1 exit status

Я посмотрел на эту ошибку, и, похоже, это связано с тем, что приложение C не имеет доступа к библиотекам STL, но если мы изменим main.c, чтобы сделать только вызов GetAPIMajorVersion() и удалить функцию GetAPIMinorVersion() из библиотека. Приложение компилируется и запускается как положено.

Это наводит меня на мысль, что проблема не в библиотеке STL в целом, а в некоторых функциях библиотеки STL.

Мое следующее предположение: возможно, что функция std::vector<bool>::push_back() может выдать исключение, и это включает элементы в библиотеку aaa.a, которую приложение C не может найти.

Если это проблема, то как мне включить обязательные части библиотеки STL в библиотеку aaa.a, чтобы она могла использоваться приложением C?

Я обнаружил, что если я изменяю приложение C для сборки с g++ вместо gcc, оно собирается и работает нормально. К сожалению, компилятор, который я использую в конце концов, поддерживает только C99, и это не вариант для меня.

g++ -m64 -Wall -static main.c -o main -L./ -laaa 

Как мне построить эту библиотеку, которая включает функции STL, таким образом, чтобы функции библиотеки можно было вызывать из приложения C?

Редактировать

  • В конце я использую компилятор Arm Keil
  • Похоже, нет возможности включить stdc++ в качестве библиотеки в IDE / компилятор Arm Keil. Насколько мне известно, я не могу изменить команду для сборки приложения C на gcc -m64 -Wall -static main.c -o main -L./ -laaa -lstdc++.

1 Ответ

0 голосов
/ 02 ноября 2018

Вы можете попробовать создать библиотеку C ++ shared , linking -lstdc++.

Итак, пусть -laaa будет совместно используемой библиотекой libaaa.so (из исходных файлов aaa1.cc и aaa2.cc и имеющим позиционно-независимый код ), который вы создадите с:

 g++ -fPIC -O3 -g aaa1.cc -o aaa1.pic.o
 g++ -fPIC -O3 -g aaa2.cc -o aaa2.pic.o
 g++ -fPIC -shared -O3 -g aaa1.pic.o aaa2.pic.o -lstdc++ -o libaaa.so

Вы также можете установить rpath .

Чтение Как библиотека программ и Drepper's Как писать общие библиотеки

Компилятор, который я использую в конце, это Arm Keil

Вместо них лучше использовать недавнюю версию GCC кросс-компилятора (или Clang one). Либо вы создаете этот кросс-компилятор самостоятельно из исходного кода GCC 8 (осенью 2018 года), либо устанавливаете какой-либо кросс-компилятор в свой дистрибутив Linux. Например, Debian / Sid имеет gcc-8-arm-linux-gnueabi и gcc-8-arm-linux-gnueabihf

Опытные производители оборудования предоставляют древние кросс-компиляторы (и не очень хороши в разработке программного обеспечения). Вот почему я рекомендую использовать в командной строке недавний GCC кросс-компилятор.

И вам лучше связать ваше приложение с g++.

Мое следующее предположение: возможно, функция std :: vector :: push_back () может выдать исключение

Исключениям требуется некоторая поддержка на уровне crt0 (для std :: terminate ). Если ваша библиотека выдает какое-то исключение, основная программа должна быть связана с g++ (если вы хотите использовать библиотеку C ++ из C, она не должна выбрасывать исключение снаружи).

Однако, возможно, с некоторой осторожностью, создать библиотеку C ++, пригодную для использования из gcc -компилированного кода C. libgccjit - это такая библиотека (но она не создает исключений снаружи).

Насколько мне известно, я не могу изменить команду для сборки приложения C на gcc -m64 -Wall -static main.c -o main -L./ -laaa -lstdc ++

Вы, конечно, могли бы. Вам следует избегать использования Arm Kell и использовать непосредственно соответствующий кросс-компилятор в командной строке (либо тот, который находится внутри него, либо, желательно, более новый, который вы строите из исходного кода GCC или Clang).

...