从C ++类创建LLVM字节码

时间:2011-06-23 11:01:39

标签: c++ llvm bytecode clang

我正在为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;
}

但这将是一项繁琐的工作。有没有办法从我的库源创建有用的字节码呢?或者在我的编译器中使库可用的任何其他方法?

2 个答案:

答案 0 :(得分:6)

您可以看到clang是否尊重显式模板实例化的外部链接。这可能适用于非模板,但您可以“强迫它”用于模板。

简单概要:

lib1.h

template <typename T=int>
struct ATemplate { T f() { return 123; } };

添加文件 lib1_instantiate.cpp

#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;
}

然而

  1. 转换为(void *)会调用未定义的行为(您无法在gcc上使用-pedantic -Werror编译它)
  2. 对于重载,您必须指定丑陋的强制转换才能消除它们的歧义
  3. HTH

答案 1 :(得分:0)

如果只想使用一些库函数,则可以使用另一种方法:为您使用的所有内容创建一个包装器。

// wrapper.cc
A* A_create() {
    return new A();
}

// and so on

这样你就不必修改你的库了,但这绝对是一些额外的输入。