当前位置: 首页 > 工具软件 > Calypso > 使用案例 >

d与C++的绑定的Calypso工具

越骏俊
2023-12-01

Calypso工具,地址
它的工作方式与htod.exe类似,Calypso生成extern(C++).
它与clang++绑定在一起.
这不是Calypso现在的工作方式,它通过'modmap(C++)"dll头文件.h"',直接从D模块导入C++头文件,而不生成中间的D绑定模块:
这里,基础c++绑定生成,用来生成qt绑定.
unwashed会把D看作是一种只在clang++支持的平台上才可行的语言.Qt/vtk/数字库.
目标是让Qt,VTK,线性代数,矩阵等都能在D(LinuxWindows)中使用,我并不担心它是如何完成的
Calypso需要dmd+clang++是自然的.与extern(C++)帮助,而不是替代关系.
编译器支持插件.
Ogre3D演示的第一道曙光之后,异常捕捉是下个任务,Clang可能会大大简化C++异常的处理.

1.在D中无法抓C++多态类型异常.
2.(或Calypso)为从C++抛的多态类型定义了D类对应项,特别是std::exceptionsubtypes.注意,这些是D类,而不是D构.
3.D代码可抓std::exception.唯一注意,抓的异常无法在catch语句之后继续存在.考虑到调用C++并不是首要安全问题,这是合理折中.示例:

import core.stdcpp.vector;
import core.stdcpp.exception;

core.stdcpp.exception g;

void fun(core.stdcpp.vector!int v)
{
    try
    {
        v.push_back(42);
    }
    catch (core.stdcpp.exception e) // 可抓
    {
        g = e; // 悬挂
    }
}

README现在应该更清楚Calypso应做什么,有用模板部分显式规范示例改进和扩展的展示例的链接,并解释了如何构建它并链接C++库.

假定,

//test.cpp
int foo(unsigned *p);

如何使用CalypsoD?

...这里发生了什么?
uint x;
foo(&x);

然后是:

$ clang++ -std=c++11 -c showcase.cpp -o showcase.cpp.o
$ ar rcs libshowcase.a showcase.cpp.o
$ ldc2 -cpp-args -std=c++11 -Llibshowcase.a -L-lstdc++ showcase.d

Calypsoldc2的一部分,据我所知,是通过"-cpp-args"壳参数调用的.
下面是最简单说明如何使用上面函数的示例:

//test.h
namespace test {
  int foo(unsigned int *p);
}

//test.cpp
#include "test.h"
int test::foo(unsigned int *p)
{
  return *p * 2;
}

//test.d
modmap(C++) "test.h";
import(C++) test._;  //导入全局变量,函数和`typedef`
import std.stdio;

void main()
{
  uint x = 4;
  writeln("foo = ", foo(&x));
}

我测试过更复杂示例,运行得很好.目前,我在Calypso中遇见的最大的警告是,所有东西都必须在一个名字空间中.因此test.h有一个有点多余"test"名字空间.据我所知,要使用Calypso,必须有它.
导入'C++'库时,如果只使用.h文件(如包含一些类的美化C头文件)或类似,不封装在唯一的名字空间中,这是个问题.

-cpp-args仅用于在生成预编译头时传递参数给Clang.
Calypso把自己注册为"语言插件",当parse.c遇到import(ABC)xxx.yyy时;它询问是否注册有处理"ABC"语言的插件.如果有,它让插件创建Import符号,如Calypso创建了从Import继承的cpp::Import,并且有个不会在.d文件中查找模块而是在Clang生成的PCH中查找模块完全不同load()方法.
下面是LangPlugin接口:

class LangPlugin
{
public:
 //如果`此插件`不处理所述语言,返回`-1`,否则返回传递给createImport的`id`号
    virtual int doesHandleModmap(const utf8_t *lang) = 0;

    virtual Modmap *createModmap(int langId,Loc loc, Expression *arg) = 0;

 //如果`此插件`不处理所述树,返回`-1`,否则返回传递给createImport的`id`号
    virtual int doesHandleImport(const utf8_t *tree) = 0;

    virtual Import *createImport(int treeId,Loc loc, Identifiers *packages, Identifier *id,Identifier *aliasId, int isstatic) = 0;

    // ===== - - - - - ===== //

    virtual Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad,Expression *e1, Declaration *var, int flag = 0) = 0;

    // ===== - - - - - ===== //

    virtual FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc) = 0;
    virtual FuncDeclaration *buildCpCtor(StructDeclaration *sd, Scope *sc) = 0;

    // ===== - - - - - ===== //

     virtual CodeGen *codegen() = 0;
};

getRightThis,buildDtorbuildCpCtor是必须的,因为它们"覆盖"了具有相同名称的全局函数.
Andrei通用插件系统问题,我不知道如何构建.为Calypso创建的钩子是C++特有的,只是简单开放钩子(并不是真正的侵入性,除了一两个可能会以不同的方式完成的钩子,也不会使代码丑陋):勾挂只是强制复制冗余基函数,对大的语义函数,很差.
使用结构不是更容易吗?它们只缺少一个继承特性,而缺少值类型所必需的许多特性:值类型和确定性析构.

工作原理如下:
给定C++头文件foo.h:

void bar(unsigned *);

C++源文件foo.cpp:

void bar(unsigned *p) { }

我想在从test.d中调用bar():

void main() {
    uint x;
    bar(&x);
}

以下是如何使用Calypso:

module test;

modmap (C++) "foo.h";
import (C++) _ : bar;

void main() {
    uint x;
    bar(&x);
}

编译和链接:

clang++ foo.cpp -c
ldc test.d foo.o

生成可运行"test"程序.
Calypso不是独立的工具.它是LDC允许你在不需要绑定或中间文件,就直接导入/包含,C++头文件,并使用D中的声明一个分支.
可不必编写绑定直接对接C++库的经过修改LDC.

 类似资料: