在C应用程序中运行C++(带有STL)函数

Running C++ (with STL) functions in a C application

本文关键字:带有 STL 函数 C++ 应用程序 运行      更新时间:2023-10-16

我正在创建一个C++库,其中包含使用某些STL功能的导出C函数。我想把这个库包含在C应用程序中。

我已经尽我所能将这个问题简化为以下4个文件。

main.c

#include "aaa.h"
#include <stdio.h>
int main()
{
printf("Version: %u.%un", 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应用程序找不到的元素。

如果这是问题所在,我该如何在aaa.a库中包含STL库的必需部分,以便C应用程序可以使用它?

我发现,如果我将C应用程序更改为使用g++而不是gcc构建,它就会构建并运行良好。不幸的是,我最终使用的编译器只支持C99,这对我来说不是一个选项

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

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

编辑

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

您可以尝试构建一个C++共享库,链接-lstdc++

因此,让-laaa是一个共享libaaa.so(来自源文件aaa1.ccaaa2.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的如何编写共享库

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

您最好使用一些GCC交叉编译器(或Clang编译器(的最新版本。要么你自己用GCC 8的源代码构建交叉编译器(2018年秋季(,要么在Linux发行版上安装一些交叉编译器。例如,Debian/Sid有gcc-8-arm-linux-gnueabigcc-8-arm-linux-gnueabihf

根据经验,硬件供应商提供古老的交叉编译器(在软件工程方面并不好(。这就是为什么我建议在命令行上使用最新的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-one构建的最新交叉编译器(。