原文
导入用'-betterC'
单独编译的XYZ
模块,会有因为缺少应由XYZ
模块定义的叫__ModuleInfo
的符号的链接器错误
.
一种补救
方法是在XYZ
中定义此值:
extern(C) __gshared ModuleInfo _D3dmd7backend7ptrntab12__ModuleInfoZ;
导入
模块会依次
添加所有导入模块
的引用
,参见.object.ModuleInfo
中定义的importedModules
属性的定义.
这真是问题吗?为啥要用-betterC
编译D库
,然后在D程序中
使用它?
一个用例是dmd
编译自身
.
一般,想在D中
构建可同时使用C和D
的库.
$ dmd -betterC -lib mylib1.d mylib2.d
$ dmd -I. mylib1 myexe.d -mainmodule myexe;
import mylib2;module mylib1;
static this() {}module mylib2;
import mylib1;
为什么'mylib1'
有模块构造器?,'-betterC'
不应拒绝它吗?
有人创造性
地在更好的C
模式下,用'pragma(crt_constructor)'
制作了模块构造器
.
不是只对'shared static this'
吗?
:dmd -betterC -lib mylib1.d mylib2.d
这编译mylib1.d
和mylib2.d
,并创建包含两个
文件目标代码的mylib.lib
库文件.
:dmd -I. mylib1 myexe.d -main
这会把mylib1.d
和myexe.d
编译在一起,形成mylib1.exe
的可执行
文件.因为命令行
中没有给出,它无法从mylib2.d
中找到内容.这不是编译器
错误.
我想应,创建放入mylib1.d
和mylib2.d
编译版本的mylib1.obj
:
dmd -betterC mylib1.d mylib2.d
而,
dmd -I. myexe.d mylib1.obj -main
编译myexe.d
并链接到mylib1.obj
,来创建叫myexe.exe
的可执行文件.或至少这样做,但给出:
myexe.obj(myexe)Error 42: Symbol Undefined __D6mylib212__ModuleInfoZ
因为-betterC
抑制生成ModuleInfo
,而myexe.d
却期望它.这是编译器
错误,或至少是编译器
问题.
如果以下至少有一个为真
,模块
就会产生ModuleInfo
:
1
.它导入生成ModuleInfo
模块.
2
.它有个静态构造器
3
.它有静态析构器
4
.它有单元测试
声明
但如果启用了-betterC
,则会禁止
生成,本问题,是由于有静态构造器
的问题.
Iain
的想法是正确
的.在-betterC
模式下,解决方法是:
1
.使用以下来自动注解静态构造器
:
pragma(crt_constructor) extern (C)
2
.对静态析构器
同样
3
.对(1)
和(2)
不设置'needmoduleinfo'
.
这会用C运行时库
机制运行构造器和析构器
.缺点
是按链接器
看到的目标
文件顺序,而不是深度优先
层次顺序构造和析构
.
Mathias
的建议很好.在'static this()'
上给出错误,并仅在'shared static this()'
上工作.
mylib1.d
中有个静态构造器
.何时构造?
在C代码中,C
运行时按它们在链接器
中顺序来处理.
在D代码中,D
启动代码,会在C运行时
初化*之后*
按深度
优先级处理.
两者
是不同的,且是不可调和
的(尽管大多数静态构造器
可能不关心顺序,但不能依赖它).
myexe.d
无法知道它正在导入更好C
模块,因此它无法正确处理构造.
因此,提出另一种方法.mylib1.d
只需选择是C构造
还是D构造
.C构造
将是:
pragma(crt_constructor) extern (C) static this() { ... }
而D构造
:
static this() { ... }
myexe.d
在看到D静态构造器
时,需要来自mylib1.d
的ModuleInfo
.编译器在用-betterC
编译mylib1.d
时,且看到D静态构造器
时,则可为该静态构造器
创建ModuleInfo
.
为更好C和D
程序,创建更好C
库,用:
pragma(crt_constructor) extern (C) static this() { ... }
D模块构造器
当然不应在betterC代码
中工作.它们可抛死码
警告,因此不需要生成ModuleInfo
(这应该很容易解决).这避免未来
意外.
然而,根本
问题是按需
付费运行时
,在-betterC
中,需要ModuleInfo
时,不能按需付费的打开
它.
现在无法打开生成ModuleInfo
,因为DllImport
不完整(实现难).如果现在开启
它,exe
与带D
的dll
运行时,会有段错误
.
应该先解决DllImport
问题,然后用此代码
作为测试用例
来验证
,是否确实修复
它,而不是先修复本漏洞
.
本例中,ModuleInfo
是D运行时
如何运行静态构造器
.用betterC
编译的程序只能与对ModuleInfo
一无所知的C运行时
库链接.
问题是编写用betterC
编译的库,并与betterC
程序或D程序
链接.
简单关闭生成ModuleInfo
,表明betterC
的库不运行
它的静态构造器
.
由于导入betterC
模块的D程序
不知道它们是否是betterC
模块,因此betterC
模块选择如何静态
构造.
即,更好C
模块应用以下
代码来运行其静态构造
:
pragma(crt_constructor) extern (C) void doMyStaticConstruction() { ... }
如果更好C
只与D主
连接,它应该:
static this() { ... }
但不应同时执行这两个
操作,因为如果同Dmain
链接,则静态
构造了两次.
修复该错误报告的改变是,对betterC
模块,如果有'static this'
构造器就生成ModuleInfo
,并在文档
中添加这些指令
.导出DLL
是个正交
问题.
这不应
是自动的.
-betterC
是一个开关
的集合.其中之一是关闭生成ModuleInfo
.这是它在LDC
和GDC
中的工作
方式.
它需要通过开关
选入.否则,可能会有意外
.
与打开或关闭生成ModuleInfo
相比,最好触发不触成ModuleInfo
.
如,如果写了静态构造器
,且抑制了ModuleInfo
,程序仅链接但不会执行
静态构造器,使程序不如期望
.
进一步思考:
因为ModuleInfo(A)
会在runtime
中生成调用_d_so_registry
,betterC
代码不能生成(A
).
在更好C
模块中有个'static this'
,或在更好C
模块中导入带有'static this'
的模块,需要ModuleInfo
来保证语义.简单地关闭生成ModuleInfo
,会链接程序,但运行时未运行static this
,即代码不工作.
相反,betterC
代码必须用pragma(crt_constructor)
函数,而不是静态初化
.由C运行时
启动代码调用这些函数.
依赖pragma(crt_constructor)
表明修复
报告问题,并确保正确定义.1链接
之后是,在d运行时
中,尽量用pragma(crt_constructor)
替换static this
.在此