我正在使用导出的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应用程序中调用该库函数?
修改
g++ -m64 -Wall -static main.c -o main -L./ -laaa
作为库包含在内。据我所知,我无法更改将C应用程序构建为stdc++
的命令。 答案 0 :(得分:1)
您可以尝试构建C ++ 共享库linking -lstdc++
。
因此,假设-laaa
是一个共享库libaaa.so
(来自源文件aaa1.cc
和aaa2.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-gnueabi
和gcc-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编译的最新交叉编译器)。