在C应用程序中运行C ++(带有STL)功能

时间:2018-11-01 23:20:30

标签: c++ c gcc stl

我正在使用导出的C函数(使用某些STL功能)创建C ++库。我想将此库包含在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()并删除{{1 }}函数。该应用程序将编译并按预期运行。

这使我相信问题不在于STL库,而在于STL库中的某些功能。

我的下一个猜测是,GetAPIMinorVersion()函数可能会引发异常,并且这会将C应用程序找不到的元素包含到aaa.a库中。

如果这是问题,那么我如何在aaa.a库中包括STL库的require部分,以便C应用程序可以使用它?

我发现,如果我将C应用程序更改为使用std::vector<bool>::push_back()而不是g++构建,则它可以正常运行。不幸的是,我最终使用的编译器仅支持C99,这对我来说不是一个选择。

gcc

我应该如何构建一个包含STL函数的库,以便可以从C应用程序中调用该库函数?

修改

  • 我最后使用的编译器是Arm Keil
  • 在Arm Keil IDE /编译器中似乎没有选择将g++ -m64 -Wall -static main.c -o main -L./ -laaa 作为库包含在内。据我所知,我无法更改将C应用程序构建为stdc++的命令。

1 个答案:

答案 0 :(得分:1)

您可以尝试构建C ++ 共享linking -lstdc++

因此,假设-laaa是一个共享libaaa.so(来自源文件aaa1.ccaaa2.cc,并具有position-independent code)您将使用的构建方式:

 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

阅读Program Library HowTo和Drepper的How to write shared libraries

  

我最后使用的编译器是Arm Keil

您最好改用GCC交叉编译器(或Clang交叉编译器)的 recent 版本。您可以根据GCC 8的源代码自己构建交叉编译器(在2018年秋季),或者在Linux发行版上安装一些交叉编译器。例如,Debian / Sid具有gcc-8-arm-linux-gnueabigcc-8-arm-linux-gnueabihf

根据经验,硬件供应商会提供古老的交叉编译器(并且在软件工程方面并不擅长)。因此,我建议在命令行上使用 recent GCC交叉编译器。

您最好将应用程序与g++链接。

  

我的下一个猜测是std :: vector :: push_back()函数可能会引发异常

crt0级别(对于std::terminate),异常需要一些支持。如果您的库抛出异常,则主程序必须与g++链接(如果您希望C语言库可用于C语言,则不应在外部抛出异常)。

但是,可以谨慎地构建从gcc编译的C代码中可用的C ++库。 libgccjit就是这样一个库(但它不会在外部抛出异常)。

  

据我所知,我无法将用于构建C应用程序的命令更改为gcc -m64 -Wall -static main.c -o main -L./ -laaa -lstdc ++

您肯定可以。您需要避免使用Arm Kell,而直接在命令行上使用适当的交叉编译器(要么在其内部提供的交叉编译器,要么最好是从GCC源代码或Clang编译的最新交叉编译器)。