2404d,d符号表示dip1045

news/2024/5/9 10:06:45/文章来源:https://blog.csdn.net/fqbqrr/article/details/137614108

原文

符号表示

概述

符号是本地语言功能最终表示.在编译器或语言级别,不准确表示它们可能会导致链接失败.这些问题可能是令人沮丧的重要来源,甚至可能导致人们认为无法实现方法.

DIP的目的是解决和纠正各种跨平台和目标的常见共享库链接错误.

理由

对不熟悉链接器的人来说,理解和解决这些错误可能令人生畏,一般会导致寻求帮助.

仅限于静态库和独立可执行文件使用语言时,D中的很大一部分符号的表示问题仍模糊不清.但是,此配置并不能满足所有用户的不同需求和偏好.

需要更灵活的如涉及共享库的二进制配置.

把插件整合D中,为其他语言创建D插件或开发可替换二进制文件等用例,都说明了涉及D的共享库有益的场景.为了确保D一致性和易用性,增强语言的符号表示方法至关重要.

主要焦点应放在模块级别.默认,了解模块是在当前二进制文件内部还是外部,是解决许多链接器问题的关键.这些基本知识为进一步改进和修改奠定了基础.

前期工作

2016年,BenjaminThautDConf上发表了题为"D的导入出业务"的演讲,提出了改进D语言特别是导出和共享库功能的提案.

虽然该DIP并非直接源自Thaut的提议,且具体实现细节不同,但它在导出的作用上得出了类似结论.

即,它认识到,为了在D中有效利用注解,导出不应仅按可见性限定器使用.

Thaut方法的一个显著区别是,他建议设置dllimport开关为"all",来指示符号是在DllImport模式.

然而,根据D社区随后几年中在共享库方面的丰富经验,很明显,该方法经常导致链接器错误.因此,需要一个更细致,更细粒度方法来有效解决这些问题.

描述

变更基石

本节概述未来更新关键更改,以确保无误编译.

1,外部导入路径开关:

引入了新的extI编译器标志.它的功能类似I开关,按当前正在编译二进制文件外部,指定模块.

最好,构建管理器可自动执行此过程,对共享库关联的模块,用依赖关系的知识-extI替换-I.

2,二进制外模块:

(通过-extI开关)按外部标识的模块,对所有非模板化域,有个隐式的extern属性.

3,导入符号:

要按DllImport模式导入符号,需要同时有exportextern注解.此时,是否存在函数体不重要.

以下各节,考虑模板在与共享库,D接口生成器,不同的导出注解内联链接时的可靠性.

模板的可靠性

因为实例化模板的假设,模板可能会导致链接失败.因此,确保从模板继承的符号不会自动符合导出条件或为DllImport模式.

相反,按二进制文件的外部标识这些符号时,应重新实例化,并在设置了适当的重复标志后,放入目标二进制文件中.

这要求在每个模块基础上,应用外部导入路径开关.

为了优化生成代码,编译器可用"固定"策略.如果在其声明的同一模块中,非模板化符号引用了模板实例化(a),则按"固定"对待a.

固定扩展到在模板中未封装变量声明(包括全局变量)及函数参数和返回类型.

固定模板及其关联的符号后,在这些符号二进制文件的外部时,编译器可自行决定,是否省略这些符号的生成代码.此时,编译器应遵循指定的导出DllImport符号模式,以确保高效且无错误的链接.

D接口生成器

D接口生成器是D编译器提供的导出工具,通过省略D文件中的符号体来方便创建.di文件.
当与C解析器(ImportC)一起使用,以生成C库绑定时,此工具特别有用.

但是,当前实现的一个显著局限性是在导出过程中,它无法准确遵循符号模式.

为此,提出了以下修改建议:
1,生成器,不应自动添加extern属性到符号中.
2,仅当按导出特定模块设置可见性覆盖开关时,生成器才可把导出(export)属性添加到所有非模板化域.

这些调整旨在与前面概述变更基石相结合.用来确保:
1,对按export标记的代码基,.di生成器限制引入其他extern属性.
2,对静态库或目标文件,生成的.di文件可同-I标准导入路径开关一起使用.
3,或,在处理共享库依赖项时,可把外部导入路径开关-extI应用至.di文件.

导出符号模式方法

每个符号可有三个不同模式之一:Internal,DllExportDllImport.

1,内部模式:这是符号的默认模式.不管在哪个模块中定义,同一个二进制文件中的其他符号都可访问内部符号.
2,DllExport模式:设置后,此模式指示,不仅自己的二进制文件,且外部二进制文件都可访问符号.这对编译打算跨不同二进制文件使用的符号至关重要.
3,DllImport模式:此模式告诉编译器符号当前二进制文件的外部.因此,编译器生成允许在运行时访问此符号代码.

确定符号适当模式策略如下:
1,使用export正注解:此方法表示D编译器的默认行为,即对导出,用export关键字来显式标记符号.
2,用可见性覆盖开关负注解:默认,不会导出未用导出(export)注解的符号.可用可见性覆盖开关来反转此默认,来强制导出所有符号.对未显式标记导出,但需要导出其符号的特别有用.

3,多步构建边角注解:这是个特定注解,适合需要(具体根据构建步骤)确定符号Internal还是DllImport的方案.
在复杂或冲突的符号模式多步构建过程中非常有用.

导出注解

按参数取标识,来增强导出属性.按版本解释标识,需要以下语法更改:

VisibilityAttribute:
-   export
Attribute:
+   export
+   export ( Identifier )

此参数的功能根据标识是否活动(由version=ident激活).活动时,除非正在编译,符号内部模式.相反,当标识非活动时,类似有外部(extern)注解,符号按DllImport模式.

为了标准化标识使用,在D规范引入了三个新的版本前缀,编译器自动提供了libc,DRuntimePhobos实例:
前缀为Have_,InBinary_Compiling_.这三个后缀将是个逻辑包.

1,Have_前缀:指示在链接过程中,指定逻辑包可用作依赖项.
2,InBinary_前缀:表示当前正在编译二进制文件中有指定逻辑包的符号.
3,Compiling_前缀:表示正在编译指定逻辑包.

这些前缀结合逻辑包后缀,可处理按内部而不是外部的符号的极端场景.

此外,会更新D接口生成器,以支持插入InBinary_version参数.需要此更新才能通过D模块准确表示C文件.此处未介绍确定后缀的具体机制,它可能依赖于C预处理器功能.

正表示法

D中的export属性用于按DllExport来注解符号.要表示已导出符号,应直接应用此属性D符号.

导出注解不能按可见性限定器使用.这样处理它,可能会无意中暴露内部实现细节,可能会在语言级别,导致外部实体代码基不安全的操作.

在(如构,类,联或模块)封装单元中,如果按export标记任一成员,则也还必须导出所有关联生成的符号(如TypeInfo,__initZ,opCmp等,但不包括ModuleInfo).

导出关联符号,却无法导出这些生成符号时,则可能导致链接器错误,则如果不借助链接器脚本,可能无法解决这些错误.

默认,所有符号都是隐藏的.要按隐藏显式标记符号,请用core.attributes中提供的用户定义属性(UDA).该方法比在要导出每个符号注解导出更有效.

相反,它允许你在域级注解,并简单禁止那些不打算导出的符号.

否定符号

设置可见性覆盖开关后,默认导出所有符号.
覆盖默认设置,并按隐藏显式指定符号,应使用core.attributes中提供的UDA.

在适当对DRuntimePhobos库,用导出全面注解并测试前,它们依赖此符号可见性管理方法.

内联

考虑一个二进制外模块:

pragma(inline, true)
export extern void inlineable() {noInline;
}
@hidden void noInline();

在此例中,按隐藏标记noInline函数,因此无法访问内联.如果可跨二进制边界内联inlineable,因为noInline不可用,这会导致链接器错误.

为了避免此类错误,当这些函数引用未导出的符号时,必须指示编译器不要内联二进制外模块的函数.

用例

本节介绍场景说明了本DIP中提议的修改实际影响和应用.
第一个情况与需要细致控制导出符号用户有关.
第二个重点是,无需调整符号的DllImport状态,方便整合DRuntime二进制文件.

正注解

用例概述了用导出正注解和可选使用.di生成器的过程.它使用窗口文件命名约定展示.
目录布局:

dependency/source/library.d
dependency/imports/library.di
dependency/library.dll
dependency/library.lib
dependency/library.exp
executable/source/app.d
executable/app.exe
executable/library.dll

dependency/source/library.d的源:

module library;
export void myLibraryFunction() {import std.stdio;writeln("Hello from my libraries function!");
}

生成的dependency/source/library.di:

module library;
export void myLibraryFunction();

executable/source/app.d:

module app;
void main() {import library;myLibraryFunction();
}

使用共享库:

dmd of=dependency/library.dll shared Hd=dependency/imports dependency/source/library.d
cp dependency/library.dll executable/library.dll
dmd of=executable/app.exe extI=dependency/imports executable/source/app.d dependency/library.lib

使用静态库:

dmd of=dependency/library.lib Hd=dependency/imports dependency/source/library.d
dmd of=executable/app.exe I=dependency/imports executable/source/app.d dependency/library.lib

使用共享库和静态库的主要区别在于,编译前者时包含-shared,而在链接后者时用-I替换-extI.

二进制中的DRuntime

用例侧重于整合DRuntime二进制文件中的过程.不考虑Phobos等其他库,只是个说明性示例,因为,在静态或共享DRuntime间选择的开关是编译器相关的.

对此用例,考虑把DRuntime放入生成的二进制文件中会怎样.不考虑其他库(如Phobos),且选择Druntime静态的还是共享的开关是编译器相关的,因此它只是演示了它的流程.

目录布局:

dependency/source/dependency.d
dependency/dependency.lib
mydll/source/api.d
mydll/mydll.dll
mydll/mydll.lib
mydll/mydll.exp

dependency/source/dependency.d的源:

module dependency;
void myLibraryFunction() {foreach(m; ModuleInfo) {//非模板化的符号都适合此例!}
}

mydll/source/api.d的源:

module api;
export void api() {import dependency;myLibraryFunction();
}

编译命令:

dmd of=dependency/dependency.lib lib libdruntime=static dependency/source/dependency.d
dmd of=mydll/mydll.dll shared I=dependency/source libdruntime=static mydll/source/api.d dependency/dependency.lib

特别令人感兴趣的是-lib-druntime=static的行为.
在典型的D编译中,会自动添加导入路径静态/导入库.使用此DIP,要指定共享DRuntime版本,则用-extI替换-I,用导入库替换静态DRuntime库,并按externalOnly设置覆盖dllimport.

该方法大大简化了共享和静态DRuntime之间的区别,可能允许编译器配置文件掩盖这些差异.

目前,未使用export注解DRuntime.如果是,则不必添加-dllimport=externalOnly,从而降低链接器试访问未导出符号的风险.

DIP旨在消除在当前环境中使用有共享DRuntime共享库时很常见的(如LNK4217)链接器警告.

重大更改和弃用

导出不再表示"超级公开"的可见性.可能会影响现有代码中符号的可见性和可访问性.

为了缓解此潜在问题,可在使用导出前的行中添加public:调整代码基.此方法向后兼容,确保它与当前和未来编译器一起正常运行.

对那些喜欢保留传统导出行为的人,建议这样.

DIP中建议的所有其他修改基本上都是通过-extI编译器开关选入的.

参考

在C和C++中,一般通过宏预处理器交换的属性来选择DllExportDllImport.它虽然实用,但很麻烦,需要配置每个库.

Rust使用一个包括库名,可通过命令行参数调整的link属性,以在编译过程中切换默认符号模式.此DIP引入了版本命名约定InBinary_,来指定包是在二进制文件内部还是外部.

与配音使用的现有Have_约定一致,并利用了D的现有机制.

二进制外:不在当前编译二进制文件中的符号.如果按DllExport模式设置,并通过DllImport访问,则当前正在编译的二进制文件可在运行时访问它.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_1045609.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AOF文件重写

1.2.3.AOF文件重写 因为是记录命令,AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。 如图&am…

穿越代码之海:探寻结构体深层逻辑,展望未来应用新天地

欢迎来到白刘的领域 Miracle_86.-CSDN博客 系列专栏 C语言知识 先赞后看,已成习惯 创作不易,多多支持! 结构体作为一种数据结构,其定义和特点决定了它在各种应用中的广泛适用性。随着科技的进步和新兴行业的不断涌现&#xf…

C语言—每日选择题—Day68

第一题 1、运行以下C语言代码&#xff0c;输出的结果是&#xff08;&#xff09; #include <stdio.h> int main() {char *str[3] {"stra", "strb", "strc"};char *p str[0];int i 0;while(i < 3){printf("%s ",p);i;} retur…

【Gem5】获取构建教程

gem5-tutorial-hpca-2023 1 介绍 1.1 Gem5是什么1.2 Gem5可以用来做什么1.3 获取并构建gem5 gem5-tutorial-hpca-2023 打开网址&#xff1a; github 创建教程代码空空间 “Code” -> “Codespaces” -> “Create Codespace on master” GitHub Codespaces 是一个由…

Java Swing游戏开发学习23

内容来自RyiSnow视频讲解 这一节讲的是Character Status角色状态或属性。 前言 这一节讲的是实现角色状态或属性的显示&#xff0c;就有点像RPG游戏中&#xff0c;人物属性显示的面板&#xff0c;其中有玩家的装备、玩家的等级&#xff0c;各种防御值、闪避值、跑速什么的。…

探索进程控制第一弹(进程终止、进程等待)

文章目录 进程创建初识fork函数fork函数返回值fork常规用法fork调用失败的原因 写时拷贝进程终止进程终止是在做什么&#xff1f;进程终止的情况代码跑完&#xff0c;结果正确/不正确代码异常终止 如何终止 进程等待概述进程等待方法wait方法waitpid 进程创建 初识fork函数 在…

Vue3_2024_7天【回顾上篇watch常见的后两种场景】___续

Vue3中监听多条数据的两种使用 1.watch【使用上一章写法&#xff0c;监听两个属性&#xff0c;然后执行相应操作…】 2.watchEffect【相对于使用watch&#xff0c;watchEffect默认页面初始加载&#xff0c;有点类似加配置&#xff1a;立即执行 immediate】 代码&#xff1a; …

单链表专题

文章目录 目录1. 链表的概念及结构2. 实现单链表2.1 链表的打印2.2 链表的尾插2.3 链表的头插2.4 链表的尾删2.5 链表的头删2.6 查找2.7 在指定位置之前插入数据2.8 在指定位置之后插入数据2.9 删除pos节点2.10 删除pos之后的节点2.11 销毁链表 3. 链表的分类 目录 链表的概念…

Qt小案例

工程概述 MainWindows 还是 Widget 在 Qt 中&#xff0c;创建 "MainWindow" 与 "Widget" 项目的主要区别在于他们的用途和功能范围&#xff1a; 1. MainWindow &#xff1a;这是一个包含完整菜单栏、工具栏和状态栏的主窗口应用程序框架。它适合于更…

python画图Matplotlib和Seaborn

python画图Matplotlib和Season 一、Matplotlib1、介绍2、安装3、内容二、Seaborn1、介绍2、安装3、内容一、Matplotlib Matplotlib官网 1、介绍 Matplotlib 是一个 Python 的绘图库,用于创建高质量的二维图表和一些基本的三维图表。它广泛应用于科学计算、数据分析、工程学和…

泛微OA 自定义多选浏览框

1、建模引擎-》应用建模-》表单 2、建模引擎-》应用建模-》模块 3、建模引擎-》应用建模-》查询 4、把查询页面挂到前端页面。 效果展示&#xff1a; 5、建模引擎-》应用建模-》浏览框 6、流程表单中字段应用

IP-GUARD内置用户系统同步飞书组织架构使用说明

一、功能简介 实现将飞书的通讯录组织架构同步到内置用户系统。 二、功能配置 2.1 飞书创建自建应用 在浏览器上打开飞书开放平台 https://open.feishu.cn ,登录管理员账号后点击开发 者后台 在开发者后台点击创建企业自建应用,填写自建应用程序名称以及描述,设置图标,点…

SSRF靶场

SSRF概述 ​ 强制服务器发送一个攻击者的请求 ​ 互联网上的很多web应用提供了从其他服务器&#xff08;也可以是本地)获取数据的功能。使用用户指定的URL&#xff0c;web应用可以获取图片&#xff08;载入图片&#xff09;、文件资源&#xff08;下载或读取)。如下图所示&…

利用Leaflet + React:构建WEBGIS

React是 Facebook 开发的一个开源库&#xff0c;用于构建用户界面。就其本身而言&#xff0c;Leaflet是一个用于将地图发布到网络的JavaScript 库。这两个工具的组合很简单&#xff0c;允许您创建动态网络地图。在本文中&#xff0c;我们将看到这种组合的一些特征以及一些简单的…

【MySQL数据库 | 第二十五篇】深入探讨MVCC底层原理

前言&#xff1a; 在当今互联网时代&#xff0c;数据库扮演着数据存储和管理的关键角色。对于大型Web应用程序和企业级系统而言&#xff0c;高效地处理并发访问和事务管理是至关重要的。多版本并发控制&#xff08;MVCC&#xff09;是一种数据库事务处理的技术&#xff0c;旨…

三种常见webshell工具的流量特征分析

又来跟师傅们分享小技巧了&#xff0c;这次简单介绍一下三种常见的webshell流量分析&#xff0c;希望能对参加HW蓝队的师傅们有所帮助。 什么是webshell webshell就是以asp、php、jsp或者cgi等网页文件形式存在的一种代码执行环境&#xff0c;主要用于网站管理、服务器管理、…

机器学习中的激活函数

激活函数存在的意义&#xff1a; 激活函数决定了某个神经元是否被激活&#xff0c;当这个神经元接收到的信息是有用或无用的时候&#xff0c;激活函数决定了对这个神经元接收到的信息是留下还是抛弃。如果不加激活函数&#xff0c;神经元仅仅做线性变换&#xff0c;那么该神经网…

蓝桥杯——17

学习视频&#xff1a;18-深搜的剪枝策略练习_哔哩哔哩_bilibili Q&#xff1a;找数字 #include<iostream> #include<cstring> using namespace std; int n; bool ok; void dfs(int num, int cnt) {if (cnt > 19) {return;}if (ok) {return;}if (num % n 0) {…

MySQL-基本SQL语句编写:运算符练习

运算符练习 1.选择工资不在5000到12000的员工的姓名和工资 SELECT last_name,salary FROM employees #where salary not between 5000 and 12000; WHERE salary < 5000 OR salary > 12000;2.选择在20或50号部门工作的员工姓名和部门号 SELECT last_name,department_id…

基于springboot+vue+Mysql的职称评审管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…