我正在为LLVM中的特殊用途语言编写编译器.我想为已经用C编写的库添加绑定.我的想法是将库编译为LLVM字节码(使用clang -emit-llvm -S abc.c)并在编译期间将其链接.这适用于类似的代码
// lib.c int f() { return 123; }
但是库的一部分写得像
// A.cc class A { public: int f() { return 123; } };
这导致空字节码文件.我知道我可以通过分离实现来解决这个问题:
// A.cc class A { public: int f(); }; int A::f() { return 123; }
但这将是一项繁琐的工作.有没有办法从我的库源创建有用的字节码呢?或者在我的编译器中使库可用的任何其他方法?
解决方法
您可以看到clang是否尊重显式模板实例化的外部链接.这可能适用于非模板,但您可以“强迫它”用于模板.
简单简介:
lib1.h
template <typename T=int> struct ATemplate { T f() { return 123; } };
#include "lib1.h" template struct ATemplate<int>; template struct ATemplate<unsigned int>; template struct ATemplate<long>; // etc.
这应该使用外部链接实例化命名模板.
如果您遇到非模板类,并且上面的技巧不适用于此,您可以像这样包装它:
instantiate.cpp:
namespace hidden_details { template <class libtype> struct instantiator : public libtype // derives... just do something that requires a complete type (not a forward!) { }; } template struct hidden_details::instantiator<A>;
如果运气不好,你必须“使用”内联成员才能获得外部链接.一个常见的技巧是使用这些成员的地址(您不需要实现委托的东西):
instantiate.cpp:
static void force_use_A() { void* unused = (void*) &A::f; }
然而
>转换为(void *)调用未定义的行为(你无法在gcc上使用-pedantic -Werror编译它)
>对于重载,你必须指定丑陋的强制转换以消除它们的歧义
HTH