CN114138376B - 一种在应用中加载插件的方法、计算设备及存储介质 - Google Patents

一种在应用中加载插件的方法、计算设备及存储介质 Download PDF

Info

Publication number
CN114138376B
CN114138376B CN202210083574.4A CN202210083574A CN114138376B CN 114138376 B CN114138376 B CN 114138376B CN 202210083574 A CN202210083574 A CN 202210083574A CN 114138376 B CN114138376 B CN 114138376B
Authority
CN
China
Prior art keywords
plug
version information
application
loading
version
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Active
Application number
CN202210083574.4A
Other languages
English (en)
Other versions
CN114138376A (zh
Inventor
张继德
陈可
陈斌
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Uniontech Software Technology Co Ltd
Original Assignee
Uniontech Software Technology Co Ltd
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Uniontech Software Technology Co Ltd filed Critical Uniontech Software Technology Co Ltd
Priority to CN202210083574.4A priority Critical patent/CN114138376B/zh
Priority to CN202210431692.XA priority patent/CN114780173B/zh
Publication of CN114138376A publication Critical patent/CN114138376A/zh
Application granted granted Critical
Publication of CN114138376B publication Critical patent/CN114138376B/zh
Active legal-status Critical Current
Anticipated expiration legal-status Critical

Links

Images

Classifications

    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F9/00Arrangements for program control, e.g. control units
    • G06F9/06Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
    • G06F9/44Arrangements for executing specific programs
    • G06F9/445Program loading or initiating
    • G06F9/44521Dynamic linking or loading; Link editing at or after load time, e.g. Java class loading
    • G06F9/44526Plug-ins; Add-ons
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F8/00Arrangements for software engineering
    • G06F8/70Software maintenance or management
    • G06F8/71Version control; Configuration management
    • YGENERAL TAGGING OF NEW TECHNOLOGICAL DEVELOPMENTS; GENERAL TAGGING OF CROSS-SECTIONAL TECHNOLOGIES SPANNING OVER SEVERAL SECTIONS OF THE IPC; TECHNICAL SUBJECTS COVERED BY FORMER USPC CROSS-REFERENCE ART COLLECTIONS [XRACs] AND DIGESTS
    • Y02TECHNOLOGIES OR APPLICATIONS FOR MITIGATION OR ADAPTATION AGAINST CLIMATE CHANGE
    • Y02DCLIMATE CHANGE MITIGATION TECHNOLOGIES IN INFORMATION AND COMMUNICATION TECHNOLOGIES [ICT], I.E. INFORMATION AND COMMUNICATION TECHNOLOGIES AIMING AT THE REDUCTION OF THEIR OWN ENERGY USE
    • Y02D10/00Energy efficient computing, e.g. low power processors, power management or thermal management

Landscapes

  • Engineering & Computer Science (AREA)
  • Software Systems (AREA)
  • Theoretical Computer Science (AREA)
  • General Engineering & Computer Science (AREA)
  • Physics & Mathematics (AREA)
  • General Physics & Mathematics (AREA)
  • Computer Security & Cryptography (AREA)
  • Stored Programmes (AREA)

Abstract

本发明公开了一种在应用中加载插件的方法、计算设备及存储介质,在应用中加载插件的方法在计算设备中执行,该方法包括:当监听到第一插件加载指令时,在应用中加载代理第一插件的第二插件,其中,计算设备中驻留有至少一个版本的第一插件,第二插件与各第一插件关联;获取应用运行时所依赖的开发库的第一版本信息;基于第二插件和第一版本信息,从各第一插件中确定出与第一版本信息相匹配的目标第一插件;在应用中加载目标第一插件。

Description

一种在应用中加载插件的方法、计算设备及存储介质
技术领域
本发明涉及计算机技术领域,具体涉及一种在应用中加载插件的方法、计算设备及存储介质。
背景技术
一般情况下,插件及其依赖的应用均由相同的开发库构建。应用和插件在运行时,都会将其依赖的开发库加载至内存中,当开发库进行版本升级后,例如,开发库需要进行较大幅度的功能更新,这种更新往往会破坏它原本的兼容性,为了避免对使用久版本的应用及插件产生影响,需要在系统中集成多个版本的开发库。这时,在运行应用时,如果应用与插件所依赖的开发库属于一个版本,那么内存中只会加载该版本开发库。如果应用和插件所依赖的开发库不属于一个版本,那么内存中会加载不同版本的开发库,导致插件和不同版本开发库之间的交叉依赖,换句话说,就是依赖低版本开发库的插件会运行在高版本的开发库环境中或者依赖高版本开发库的插件运行在低版本的开发库环境中,出现同一开发库的不同版本被同时加载使用的情况,由于多个版本的开发库无法同时共存,就会导致应用运行时产生异常。
发明内容
鉴于上述问题,提出了本发明以便提供一种克服上述问题或者至少部分地解决上述问题的一种在应用中加载插件的方法、计算设备以及存储介质。
根据本发明的一个方面,提供一种在应用中加载插件的方法,在计算设备中执行,该方法包括:当监听到第一插件加载指令时,在应用中加载代理第一插件的第二插件,其中,计算设备中驻留有至少一个版本的第一插件,第二插件与各第一插件关联;获取应用运行时所依赖的开发库的第一版本信息;基于第二插件和第一版本信息,从至少一个版本的第一插件中确定出与第一版本信息相匹配的目标第一插件;在应用中加载目标第一插件。
可选地,在根据本发明的在应用中加载插件的方法中,其中,在应用中加载代理第一插件的第二插件的步骤包括:基于各第一插件的配置信息,构建第二插件,配置信息至少包括各第一插件的标识、存储路径和第二版本信息;利用应用加载第二插件。
可选地,在根据本发明的在应用中加载插件的方法中,其中,获取应用运行时所依赖的开发库的第一版本信息的步骤包括:确定计算设备当前已加载的开发库;采用符号地址获取函数,从已加载的开发库中获取的第一版本信息。
可选地,在根据本发明的在应用中加载插件的方法中,其中,获取应用运行时所依赖的开发库的第一版本信息的步骤包括:读取计算设备的当前进程内容映射空间,遍历其中所有的内存符号内容;从内存符号内容中确定出第一版本信息。
可选地,在根据本发明的在应用中加载插件的方法中,其中,获取应用运行时所依赖的开发库的第一版本信息的步骤包括:确定计算设备当前已加载的开发库;采用符号地址获取函数,从已加载的开发库中获取的第一版本信息;检测是否获取到第一版本信息;若未获取到,则读取计算设备的当前进程内容映射空间;遍历进程内容映射空间中所有的内存符号内容;从内存符号内容中确定出第一版本信息。
可选地,在根据本发明的在应用中加载插件的方法中,其中,基于各第一插件的配置信息,构建第二插件的步骤包括:判断各第一插件的存储路径是否具有相同的上级目录;若具有,则将第二插件的绝对存储路径设置为各第一插件的绝对存储路径的上级目录,并在该目录下创建第二插件。
可选地,在根据本发明的在应用中加载插件的方法中,其中,基于第二插件和第一版本信息,从至少一个版本的第一插件中确定出与第一版本信息相匹配的目标第一插件的步骤包括:获取第二插件的绝对存储路径;将绝对存储路径与第一版本信息进行拼接,以得到目标第一插件的绝对存储路径;基于目标第一插件的绝对存储路径,确定出目标第一插件。
可选地,在根据本发明的在应用中加载插件的方法中,其中,基于第二插件和第一版本信息,从至少一个版本的第一插件中确定出与第一版本信息相匹配的目标第一插件的步骤包括:判断各第一插件的存储路径是否具有相同的上级目录;若不具有,则将第一版本信息与各第一插件的第二版本信息进行匹配;将匹配成功的第二版本信息对应的第一插件确定为目标第一插件。
可选地,在根据本发明的在应用中加载插件的方法中,其中,在当监听到第一插件加载指令时,在应用中加载代理第一插件的第二插件的步骤之前,还包括步骤:获取与应用对应的所有版本的开发库;针对每一版本的开发库,构建对应的第一插件。
根据本发明的又一个方面,提供一种计算设备,包括:至少一个处理器;和存储有程序指令的存储器,其中,所述程序指令被配置为适于由所述至少一个处理器执行,所述程序指令包括用于执行上述方法的指令。
根据本发明的又一个方面,提供一种存储有程序指令的可读存储介质,当所述程序指令被计算设备读取并执行时,使得所述计算设备执行上述的方法。
根据本发明的方案,通过在应用加载第一插件时,构建第一插件的代理插件,即第二插件的方式,可以动态识别出插件的依赖库版本,并针对插件做单一依赖加载,解决了同一开发库的不同版本被同时加载的现象。并且,通过本发明的自动选择第一插件版本的方案,可以做到从第二插件对目标第一插件的转发,兼容了传统的插件和适配了多版本依赖的分包型插件的加载方式。
上述说明仅是本发明技术方案的概述,为了能够更清楚了解本发明的技术手段,而可依照说明书的内容予以实施,并且为了让本发明的上述和其它目的、特征和优点能够更明显易懂,以下特举本发明的具体实施方式。
附图说明
通过阅读下文优选实施方式的详细描述,各种其他的优点和益处对于本领域普通技术人员将变得清楚明了。附图仅用于示出优选实施方式的目的,而并不认为是对本发明的限制。而且在整个附图中,用相同的参考符号表示相同的部件。在附图中:
图1示出了一种动态库的运行模式示意图;
图2示出了一种Qt的动态库插件的实现原理示意图;
图3示出了一种通过QPluginLoader类实现了插件的加载的流程示意图;
图4示出了一种程序A运行依赖关系示意图;
图5示出了根据本发明一个实施例的计算设备500的结构图;
图6示出了根据本发明一个实施例的在应用中加载插件的方法600的流程图;
图7示出了根据本发明一个实施例的第二插件的代理机制示意图;
图8示出了根据本发明一个实施例的双通道获取第一版本信息的原理示意图;
图9示出了根据本发明一个实施例中插件选择机制的原理示意图;
图10示出了根据本发明一个实施例的在应用中进行插件加载的方法流程示意图。
具体实施方式
下面将参照附图更详细地描述本公开的示例性实施例。虽然附图中显示了本公开的示例性实施例,然而应当理解,可以以各种形式实现本公开而不应被这里阐述的实施例所限制。相反,提供这些实施例是为了能够更透彻地理解本公开,并且能够将本公开的范围完整的传达给本领域的技术人员。
插件是通过遵循应用程序的接口规范而编写出来的第三方程序。应用程序需要提供能够让插件正常工作的各种服务,包括插件加载,插件应用和数据交互。插件只能依赖于应用程序才能发挥作用,而应用程序不需要依赖插件依然可以运行。由于动态库的动态加载与插件的工作原理非常相似,因此几乎所有的开发者设计插件时都使用动态库的方式。动态库是一种二进制程序文件,它能够为进程提供一种调用不属于进程本身代码的能力。
在一个具体示例中,如图1所示,图1示出了一种动态库的运行模式示意图。参考图1,动态库在程序编译时不会被链接到应用1或应用2的代码中,只有当应用1或应用2运行时使用到了动态库中的内容才进行加载。不同的程序如果使用了相同的动态库,内存中只会保存一份该动态库的实例,不会进行重复加载。可见,利用动态库进行开发应用和插件具有能够将动态库内容的链接推迟到应用1或应用2运行时期、能够实现进程间的资源共享、动态库的链接完全可控等优点。
需要说明的是,直接将动态库用作插件是完全不够的,应用设计中的插件既需要保证ABI(application binary interface,缩写为ABI,两程序模块间的接口;通常其中一个程序模块会是库或操作系统所提供的服务,而另一边的模块则是用户所运行的程序)的兼容也需要独立于应用本身而存在。换句话说,应用编译时不需要了解这个插件是否存在,运行时也不会因为缺少这一插件而导致程序启动失败。一般的动态库无法实现这些特性,随着开发者在动态库的基础上不断的升级改造,才实现了现在的插件。需要说明的是,ABI兼容指在升级库文件的时候,不必重新编译使用此库的可执行文件或其他库文件,并且程序的功能不被破坏。
Qt应用程序开发框架,被广泛应用与开发GUI(Graphical User Interface,图形用户界面)程序,其拥有两套可以创建插件的 API:1、可以对 Qt进行功能拓展的高级API,如:数据库驱动、图像格式、文本编码以及自定义样式等等;2、可以拓展Qt应用的低级API,对本身进行拓展的插件需要通过子类化适当的插件基类,实现内部的一些函数,指定一些宏等操作来实现。
在一个具体示例中,如图2所示,图2示出了一种Qt的动态库插件的实现原理示意图。参见图2,利用Qt进行插件构建时,是在编译插件时添加一些特定符号,由于Linux系统上的动态库是一种ELF格式文件(一种用于二进制文件、可执行文件、目标代码、共享库和核心转储格式文件),这种文件能够导出其中的函数符号,在加载动态库后,Qt通过识别这类文件中的函数符号从而定位到函数的内存地址,最后执行它来创建出插件类,保证了插件的独立加载。除此之外,对于设计好的插件类Qt提供了一套专有接口,这些接口的实现由开发者完成,在编译插件时链接到插件的ELF文件中。应用程序只需要关心这些接口的调用,不需要处理除了这些接口之外的其他接口,保证了ABI的兼容。
需要说明的是,对Qt应用通过插件进行拓展,需要使用QPluginLoader来加载插件,在使用时,插件可以提供任何你想要的功能,而不限于Qt功能的插件类型(如数据库驱动、图像处理)。如图3所示,图3示出了一种通过QPluginLoader类实现了插件的加载的流程示意图。首先,QPluginLoader会根据插件名称在指定目录寻找插件文件;随后,QPluginLoader会通过某些判断来识别该插件是否需要被加载,具体方式为:如果插件文件存在且内存中没有加载此插件,QPluginLoader会通过dlopen函数加载插件,如果已经加载了此插件,QPluginLoader就会跳过dlopen的环节;其次,当程序使用到这个插件中的内容时,QPluginLoader会通过dlsym函数寻找插件中的特定符号。如上文中的描述,这个特定符号决定了插件类的创建,最后通过调用这个特定符号地址来完成对插件的加载和创建。其中,dlopen函数和dlsym函数都是dlfcn.h(dynamic linking,能够动态链接文件中的内容。头文件<dlfcn.h>声明了一些能够操作目标符号内容的函数,这些函数也可以被定义为宏。函数原型必须提供给ISOC编译器使用)中的实现体。Linux下可以使用dlopen函数加载动态库,使用dlsym函数解析动态库中的符号。
虽然上述技术能够完美应用于开发中的大部分场景,但在某些场景下也会出现美中不足的情况。例如以下描述的场景,这种场景下再次使用上面的技术就会出现很大缺陷。为了便于理解,我们将下述场景中的某些名词进行统一规定,如将一个基于Qt开发的动态库简称为“库L”、将一个依赖于库L编写的Qt插件简称为“插件P”、将一个基于Qt和库L开发的应用简称为“应用A”。
在Qt的开发过程中,当库L需要进行较大幅度的功能更新时,这种更新往往会破坏它原本的兼容性。为了避免对使用旧版库L的应用产生影响,需要系统中集成多个不同版本的库L。如果此时的库L存在多个版本,且Qt库运行时会隐式加载自身的插件P,而该插件又会将其依赖的库L加载到内存中,这里假设插件P依赖的库L版本为1.0。当应用A启动时,同样也会加载其依赖的库L,如果应用A依赖的库L和插件P依赖的库L属于同一个版本,该库在内存中也就只有一份,不会存在问题。但如果应用A依赖的库L与插件依赖的不一致,就出现了插件和不同版本开发库之间的交叉依赖,如图4所示,图4示出了一种应用A运行依赖关系示意图。需要注意的是,在图4中,a→b,说明a被b加载,或者说a依赖于b。例如,图4中,库L1.0被插件P加载,或者说插件P依赖于库L1.0。换句话说,就是依赖低版本开发库的插件会运行在高版本的开发库环境中,出现同一开发库的不同版本被同时加载使用的情况,由于多个版本的开发库无法同时共存,就会导致程序A运行时产生异常,甚至奔溃。
为解决上述现有技术中存在的问题,提出本发明的方案。本发明的一个实施例提供了一种在应用中加载插件的方法,该方法可以在计算设备中执行。图5示出了根据本发明一个实施例的计算设备500的结构图。如图5所示,在基本的配置502中,计算设备500典型地包括系统存储器506和一个或者多个处理器504。存储器总线508可以用于在处理器504和系统存储器506之间的通信。
取决于期望的配置,处理器504可以是任何类型的处理,包括但不限于:微处理器(µP)、微控制器(µC)、数字信息处理器(DSP)或者它们的任何组合。处理器504可以包括诸如一级高速缓存510和二级高速缓存512之类的一个或者多个级别的高速缓存、处理器核心514和寄存器516。示例的处理器核心514可以包括运算逻辑单元(ALU)、浮点数单元(FPU)、数字信号处理核心(DSP核心)或者它们的任何组合。示例的存储器控制器518可以与处理器504一起使用,或者在一些实现中,存储器控制器518可以是处理器504的一个内部部分。
取决于期望的配置,系统存储器506可以是任意类型的存储器,包括但不限于:易失性存储器(诸如RAM)、非易失性存储器(诸如ROM、闪存等)或者它们的任何组合。计算设备中的物理内存通常指的是易失性存储器RAM,磁盘中的数据需要加载至物理内存中才能够被处理器504读取。系统存储器506可以包括操作系统520、一个或者多个应用522以及程序数据524。应用522实际上是多条程序指令,其用于指示处理器504执行相应的操作。在一些实施方式中,在一些实施方式中,应用522可以布置为在操作系统上由一个或多个处理器504利用程序数据524执行指令。操作系统520例如可以是Linux、Windows等,其包括用于处理基本系统服务以及执行依赖于硬件的任务的程序指令。应用522包括用于实现各种用户期望的功能的程序指令,应用522例如可以是浏览器、即时通讯软件、软件开发工具(例如集成开发环境IDE、编译器等)等,但不限于此。当应用522被安装到计算设备500中时,可以向操作系统520添加驱动模块。
在计算设备500启动运行时,处理器504会从存储器506中读取操作系统520的程序指令并执行。应用522运行在操作系统520之上,利用操作系统520以及底层硬件提供的接口来实现各种用户期望的功能。当用户启动应用522时,应用522会加载至存储器506中,处理器504从存储器506中读取并执行应用522的程序指令。
计算设备500还包括储存设备532,储存设备532包括可移除储存器536和不可移除储存器538,可移除储存器536和不可移除储存器538均与储存接口总线534连接。
计算设备500还可以包括有助于从各种接口设备(例如,输出设备542、外设接口544和通信设备546)到基本配置502经由总线/接口控制器530的通信的接口总线540。示例的输出设备542包括图形处理单元548和音频处理单元550。它们可以被配置为有助于经由一个或者多个A/V端口552与诸如显示器或者扬声器之类的各种外部设备进行通信。示例外设接口544可以包括串行接口控制器554和并行接口控制器556,它们可以被配置为有助于经由一个或者多个I/O端口558和诸如输入设备(例如,键盘、鼠标、笔、语音输入设备、触摸输入设备)或者其他外设(例如打印机、扫描仪等)之类的外部设备进行通信。示例的通信设备546可以包括网络控制器560,其可以被布置为便于经由一个或者多个通信端口564与一个或者多个其他计算设备562通过网络通信链路的通信。
网络通信链路可以是通信介质的一个示例。通信介质通常可以体现为在诸如载波或者其他传输机制之类的调制数据信号中的计算机可读指令、数据结构、程序模块,并且可以包括任何信息递送介质。“调制数据信号”可以这样的信号,它的数据集中的一个或者多个或者它的改变可以在信号中编码信息的方式进行。作为非限制性的示例,通信介质可以包括诸如有线网络或者专线网络之类的有线介质,以及诸如声音、射频(RF)、微波、红外(IR)或者其它无线介质在内的各种无线介质。这里使用的术语计算机可读介质可以包括存储介质和通信介质二者。
计算设备500还包括与总线/接口控制器530相连的储存接口总线534。储存接口总线534与储存设备532相连,储存设备532适于进行数据存储。示例的储存设备532可以包括可移除储存器536(例如CD、DVD、U盘、可移动硬盘等)和不可移除储存器538(例如硬盘驱动器HDD等)。
在根据本发明的计算设备500中,应用522包括执行方法600的多条程序指令。
图6示出了根据本发明一个实施例的在应用中加载插件的方法600的流程图。方法600适于在计算设备(例如前述计算设备500)中执行。
如图6所示,方法600的目的是实现一种在应用中进行插件记载的方法,始于步骤S602,在步骤S602中,当监听到第一插件加载指令时,在应用中加载代理第一插件的第二插件,其中,计算设备中驻留有至少一个版本的第一插件,第二插件与各第一插件关联。
针对前述技术中存在的同一开发库的不同版本被同时加载的缺陷,本发明通过将插件与开发库版本一一对应的方式来解决此缺陷,换言之,有多少个开发库就有多少个版本的插件,具体地,在一些实施例中,首先,获取与应用对应的所有版本的开发库。然后,针对每一版本的开发库,构建对应的第一插件。插件的具体构建方法可参考上述图2提到的Qt的动态库插件的实现原理进行构建,在此,不再赘述。由于传统版本的Qt插件加载方式不会对插件依赖库的版本进行判断,为此,本发明提供一个设计思路,将依赖多个版本的开发库的Qt插件进行分包,即每依赖一个不同版本的开发库就针对该版本创建一个依赖于此的插件。这种方式的好处是帮助插件进行单一依赖的托管,从插件的角度解决了依赖不单一的问题。
另外,需要注意的是,第二插件作为各第一插件的代理插件,其在构建时,不依赖任何一个开发库,应用进行第一插件的加载时,首先会加载第二插件,此时,内存中只有应用、应用依赖的开发库和第二插件,不会出现同一开发库的不同版本被同时加载的问题。然后,第二插件再通过应用依赖的开发库的版本信息,确定出于该版本信息相匹配的目标第一插件,并将目标第一插件加载至内存中,这样,可以保证应用在加载插件时,应用和插件所依赖的开发库为同一版本。
在一个具体示例中,如图7所示,图7示出了根据本发明一个实施例的第二插件的代理机制示意图。参考图7,不同版本的各第一插件均托管至第二插件中,第二插件预先获取各第一插件的版本信息,再获取到应用在运行时依赖的开发库版本信息后,将对应的第一插件进行加载,代理插件的功能就像是一个插件分发器,主要用于对版本信息的管理和对真实插件的转发。第二插件能够动态识别第一插件的版本信息,对于传统的Qt插件,设计此插件能够对不同版本的Qt插件进行分包管理和动态版本加载,是对传统技术的更新和突破,能够帮助开发者在开发插件时对版本信息唯一性做更好的标识,使应用的开发库依赖具有唯一性和有效性,以此实现对各第一插件的单一依赖。
具体地,首先,基于各第一插件的配置信息,构建第二插件,配置信息至少包括各第一插件的标识、存储路径和第二版本信息。在本发明中,为了保证兼容Qt的插件加载机制,对于不同的插件,生成的代理插件(第二插件)名称和原Qt插件(第一插件)名称对应,例如,可以将第二插件命名为plugin-chooser+第一插件的名称,这样能够确保QPluginLoader首先加载进内存的是plugin-chooser的内容。并且,各第一插件一般都会存储在同一父目录下,方便加载和查询,例如,A/B/第一插件1,A/B/第一插件2等。因此,在构建第二插件时,为了方便第二插件确定第一插件,可以将第二插件的绝对路径设置为各第一插件的绝对存储路径的上级目录。具体地,判断各第一插件的存储路径是否具有相同的上级目录。若具有,则将第二插件的绝对存储路径设置为各第一插件的绝对存储路径的上级目录,并在该目录下创建第二插件。这样,当确定第二插件的存储路径后,只需获知到开发库的版本信息,将存储路径与开发库的版本信息进行拼接便可获得目标第一插件的存储路径。
在步骤S604中,获取应用运行时所依赖的开发库的第一版本信息。获取开发库版本信息是设计代理插件中最重要的环节,需要保证能够获取到应用程序正确的开发库依赖版本来确保依赖的唯一性。在本发明中,提供了两种运行时获取应用依赖的开发库的第一版本信息的方式,分别通过已加载的开发库内容和应用映射路径进行加载。以下对这两种方案分别进行介绍:
第一方面,从已加载的开发库中寻找第一版本信息:
首先,确定计算设备当前已加载的开发库。
然后,采用符号地址获取函数,从已加载的开发库中获取的第一版本信息。其中,符号地址获取函数为dlsym,使用这个函数获取已经运行的开发库某一符号地址,并获取开发库的版本号。该函数代码具体如下:
static QFunctionPointer resolve(const char *symbol)
{
#ifdef Q_OS_LINUX
return QFunctionPointer(dlsym(RTLD_DEFAULT, symbol));
#else
return nullptr;
#endif
}
//通过dlsym寻找开发库中存在的版本信息,此时的VERSION_STR_SYMBOL是已经定义好的函数符号文本。
QFunctionPointer versionStrFunc = resolve(VERSION_STR_SYMBOL);
if (versionStrFunc) {
QString versionStr = reinterpret_cast<const char *(*)()>(versionStrFunc)();
pluginName += versionStr.left(versionStr.lastIndexOf("."));
}
第二方面,通过应用映射路径进行加载:
首先,读取计算设备的当前进程内容映射空间,遍历其中所有的内存符号内容。其中,进程内容映射空间即/proc/self/maps文件,通过读取/proc/self/maps文件,遍历其中所有的内存符号内容,获取当前开发库版本信息然后返回。
然后,从内存符号内容中确定出第一版本信息。
具体实现代码如下:
tatic QString resolveFromPSM(const QString &moduleName)
{
QFile f("/proc/self/maps");
if (!f.open(QIODevice::ReadOnly))
qFatal("%s", f.errorString().toLocal8Bit().data());
QString versoinName;
QByteArray data = f.readAll();
QTextStream ts(data);
// 遍历文件中的行数据,解析出对应的版本号信息
......
return versoinName;
}
QString versoinName = resolveFromPSM(QLatin1String("dtkcore"));
if (!versoinName.isEmpty())
pluginName += versoinName;
else
当然,为避免获取第一版本信息失败,可以将上述两种获取第一版本信息的方案进行合并,形成双通道获取第一版本信息,具体如下:
首先,确定计算设备当前已加载的开发库。
然后,采用符号地址获取函数,从所述已加载的开发库中获取所述的第一版本信息。
之后,检测是否获取到所述第一版本信息。
若未获取到,则读取计算设备的当前进程内容映射空间。
之后,遍历进程内容映射空间中所有的内存符号内容。
最后,从内存符号内容中确定出所述第一版本信息。
另外,也可以先进行应用映射路径加载方案,如果获取失败,再进行从已加载的开发库中寻找第一版本信息的方案。当然,也可以两种第一版本信息获取方案同时进行。本申请对此不作限定。如图8所示,图8示出了根据本发明一个实施例的双通道获取第一版本信息的原理示意图。参考图8,当需要获取第一版本信息时,计算设备同时执行上述应用映射路径加载第一版本信息的方案和从已加载的开发库中寻找第一版本信息的方案。通过同时进行两种方案来获取第一版本信息,可以提高获取版本信息的准确率。
在步骤S606中,基于第二插件和第一版本信息,从至少一个版本的第一插件中确定出与第一版本信息相匹配的目标第一插件。前述提到,当个第一插件具有相同的上级目录时,将第二插件的存储路径设置为各第一插件的上级目录。此时,可直接获取第二插件的绝对存储路径。然后,将绝对存储路径与第一版本信息进行拼接,以得到目标第一插件的绝对存储路径。最后,基于目标第一插件的绝对存储路径,确定出目标第一插件。
当然,当各第一插件不具有相同的上级目录时,由于第二插件在构建时,已经获知了各第一插件的存储路径,因此,可将第一版本信息与各第一插件的第二版本信息进行匹配。然后,将匹配成功的第二版本信息对应的第一插件确定为目标第一插件。
在步骤S608中,在应用中加载目标第一插件。
需要说明的是,本发明中,自动选择插件的模式兼容了Qt的插件加载机制。也就是说,传统的Qt插件和适配了多版本依赖的分包型插件都能通过本发明中的方式进行加载。这种兼容性的实现就是通过了本节叙述的多版本选择机制来完成,案例中的插件选择机制的具体调用时机如9图所示,图9示出了根据本发明一个实施例中插件选择机制的原理示意图。参考图9,当Qt插件(第一插件)需要被加载时,QPluginLoader首先通过上述代理插件(第二插件)加载出真实插件(目标第一插件)的地址,调用第二插件中的create方法,QPluginLoader经代理插件来选择合适的插件进行加载,最后通过插件选择机制来完成从代理插件到真实插件的转发。
以下通过一个简单的示例代码,展示了插件选择机制的工作方式:
class ChameleonStylePlugin : public QStylePlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID"org.qtproject.Qt.QStyleFactoryInterface" FILE "chameleon.json")
public:
ChameleonStylePlugin(QObject *parent = nullptr)
: QStylePlugin(parent)
{
m_pluginProxy.reset(DPluginLoader::load<QStylePlugin>(TARGET));
}
QStyle *create(const QString &key) override
{
return m_pluginProxy m_pluginProxy->create(key) : nullptr;
}
private:
QScopedPointer<QStylePlugin> m_pluginProxy;
};
上述代码为选择机制中的部分实现,为了保证能够继续使用Qt加载插件的方式,选择机制的实现方式需要和原插件的方式类似。不同的是,此时的create函数就已经完成了对单一依赖插件的转发。这就是一个简单的插件选择机制,也可以定制一个复杂的create函数以新增更多控制信息。当然,基于Qt的高级插件都可以使用此类方式进行多版本插件选择。本申请对此不作限定。
在一个具体示例中,如图10所示,图10示出了根据本发明一个实施例的在应用中进行插件加载的方法流程示意图。该在应用中进行插件加载的方法具体如下:
1、应用加载第一插件。
2、构建第二插件。
3、第二插件获取自身的绝对路径。
4、判断是否成功获取绝对路径,若是,则进行步骤5。否,则说明插件加载错误。
5、从已加载的动态库中寻找应用依赖的开发库的第一版本信息。
6、判断是否成功获取第一版本信息,若是,则进行步骤9。若否,则进行步骤7。
7、从/proc/self/maps中匹配当前开发库的第一版本信息。
8、判断是否成功匹配出第一版本信息,若是,则进行步骤9。若否,则说明插件加载错误。
9、将第二插件的绝对路径与第一版本信息进行拼接,以形成单一依赖的目标第一插件的存储路径。
10、将目标第一插件加载至内存中。
11、判断是否加载成功,若是,则进行步骤12。若否,说明插件加载失败。
12、成功加载插件并返回插件指针。
从整体出发,可以看到所有的操作均在运行时完成,当应用开始加载Qt插件,首先加载出来的是代理插件,在完成了代理插件的所有操作之后,将真实插件指针返回,应用加载真实插件到内存中。
从局部出发,代理插件首先会获取自身的绝对路径,这是一种运行时获取当前库文件路径的方式。获取此路径的作用为:由于真实插件被代理插件进行托管,此路径能够帮助代理插件访问到真实插件的路径。如果成功得到绝对路径,代理插件就需要获取出真实插件依赖的其他库的版本信息,如果没有获取成功,则表示插件加载出错直接退出。
本发明提供的方法通过在应用加载插件时,构建代理插件的方式,可以动态识别出插件的依赖库版本,并针对插件做单一依赖加载,解决了同一开发库的不同版本被同时加载的现象。并且,通过本发明的自动选择Qt插件版本的方案,可以做到从代理插件对真实插件的转发,兼容了传统的Qt插件和适配了多版本依赖的分包型插件的加载方式。
这里描述的各种技术可结合硬件或软件,或者它们的组合一起实现。从而,本发明的方法和设备,或者本发明的方法和设备的某些方面或部分可采取嵌入有形媒介,例如可移动硬盘、U盘、软盘、CD-ROM或者其它任意机器可读的存储介质中的程序代码(即指令)的形式,其中当程序被载入诸如计算机之类的机器,并被所述机器执行时,所述机器变成实践本发明的设备。
在程序代码在可编程计算机上执行的情况下,计算设备一般包括处理器、处理器可读的存储介质(包括易失性和非易失性存储器和/或存储元件),至少一个输入装置,和至少一个输出装置。其中,存储器被配置用于存储程序代码;处理器被配置用于根据该存储器中存储的所述程序代码中的指令,执行本发明的方法。
以示例而非限制的方式,可读介质包括可读存储介质和通信介质。可读存储介质存储诸如计算机可读指令、数据结构、程序模块或其它数据等信息。通信介质一般以诸如载波或其它传输机制等已调制数据信号来体现计算机可读指令、数据结构、程序模块或其它数据,并且包括任何信息传递介质。以上的任一种的组合也包括在可读介质的范围之内。
在此处所提供的说明书中,算法和显示不与任何特定计算机、虚拟系统或者其它设备固有相关。各种通用系统也可以与本发明的示例一起使用。根据上面的描述,构造这类系统所要求的结构是显而易见的。此外,本发明也不针对任何特定编程语言。应当明白,可以利用各种编程语言实现在此描述的本发明的内容,并且上面对特定语言所做的描述是为了披露本发明的较佳实施方式。
在此处所提供的说明书中,说明了大量具体细节。然而,能够理解,本发明的实施例可以在没有这些具体细节的情况下被实践。在一些实例中,并未详细示出公知的方法、结构和技术,以便不模糊对本说明书的理解。
本领域那些技术人员应当理解在本文所公开的示例中的设备的模块或单元或组件可以布置在如该实施例中所描述的设备中,或者可替换地可以定位在与该示例中的设备不同的一个或多个设备中。前述示例中的模块可以组合为一个模块或者此外可以分成多个子模块。
此外,所述实施例中的一些在此被描述成可以由计算机系统的处理器或者由执行所述功能的其它装置实施的方法或方法元素的组合。因此,具有用于实施所述方法或方法元素的必要指令的处理器形成用于实施该方法或方法元素的装置。此外,装置实施例的在此所述的元素是如下装置的例子:该装置用于实施由为了实施该发明的目的的元素所执行的功能。
如在此所使用的那样,除非另行规定,使用序数词“第一”、“第二”、“第三”等等来描述普通对象仅仅表示涉及类似对象的不同实例,并且并不意图暗示这样被描述的对象必须具有时间上、空间上、排序方面或者以任意其它方式的给定顺序。

Claims (10)

1.一种在应用中加载插件的方法,在计算设备中执行,该方法包括:
当监听到第一插件加载指令时,在所述应用中加载代理所述第一插件的第二插件,其中,所述计算设备中驻留有至少一个版本的第一插件,所述第二插件与各第一插件关联;
获取所述应用运行时所依赖的开发库的第一版本信息,具体包括,确定所述计算设备当前已加载的开发库,采用符号地址获取函数,从所述已加载的开发库中获取所述的第一版本信息;
基于所述第二插件和所述第一版本信息,从所述至少一个版本的第一插件中确定出与所述第一版本信息相匹配的目标第一插件;
在所述应用中加载所述目标第一插件。
2.如权利要求1所述的方法,其中,所述在所述应用中加载代理所述第一插件的第二插件的步骤包括:
基于各第一插件的配置信息,构建所述第二插件,所述配置信息至少包括各第一插件的标识、存储路径和第二版本信息;
利用所述应用加载所述第二插件。
3.如权利要求1所述的方法,其中,所述获取所述应用运行时所依赖的开发库的第一版本信息的步骤包括:
读取所述计算设备的当前进程内容映射空间,遍历其中所有的内存符号内容;
从所述内存符号内容中确定出所述第一版本信息。
4.如权利要求1所述的方法,其中,所述获取所述应用运行时所依赖的开发库的第一版本信息的步骤包括:
确定所述计算设备当前已加载的开发库;
采用符号地址获取函数,从所述已加载的开发库中获取所述的第一版本信息;
检测是否获取到所述第一版本信息;
若未获取到,则读取所述计算设备的当前进程内容映射空间;
遍历所述进程内容映射空间中所有的内存符号内容;
从所述内存符号内容中确定出所述第一版本信息。
5.如权利要求2所述的方法,其中,所述基于各第一插件的配置信息,构建所述第二插件的步骤包括:
判断各第一插件的存储路径是否具有相同的上级目录;
若具有,则将所述第二插件的绝对存储路径设置为各第一插件的绝对存储路径的上级目录,并在该目录下创建所述第二插件。
6.如权利要求5所述的方法,其中,所述基于所述第二插件和所述第一版本信息,从各第一插件中确定出与所述第一版本信息相匹配的目标第一插件的步骤包括:
获取所述第二插件的绝对存储路径;
将所述绝对存储路径与所述第一版本信息进行拼接,以得到所述目标第一插件的绝对存储路径;
基于所述目标第一插件的绝对存储路径,确定出所述目标第一插件。
7.如权利要求2所述的方法,其中,所述基于所述第二插件和所述第一版本信息,从各第一插件中确定出与所述第一版本信息相匹配的目标第一插件的步骤包括:
判断各第一插件的存储路径是否具有相同的上级目录;
若不具有,则将所述第一版本信息与各第一插件的第二版本信息进行匹配;
将匹配成功的第二版本信息对应的第一插件确定为所述目标第一插件。
8.如权利要求1所述的方法,其中,在所述当监听到第一插件加载指令时,在所述应用中加载代理所述第一插件的第二插件的步骤之前,还包括步骤:
获取与所述应用对应的所有版本的开发库;
针对每一版本的开发库,构建对应的第一插件。
9.一种计算设备,包括:
至少一个处理器;和
存储有程序指令的存储器,其中,所述程序指令被配置为适于由所述至少一个处理器执行,所述程序指令包括用于执行如权利要求1-8中任一项所述方法的指令。
10.一种存储有程序指令的可读存储介质,当所述程序指令被计算设备读取并执行时,使得所述计算设备执行如权利要求1-8中任一项所述的方法。
CN202210083574.4A 2022-01-25 2022-01-25 一种在应用中加载插件的方法、计算设备及存储介质 Active CN114138376B (zh)

Priority Applications (2)

Application Number Priority Date Filing Date Title
CN202210083574.4A CN114138376B (zh) 2022-01-25 2022-01-25 一种在应用中加载插件的方法、计算设备及存储介质
CN202210431692.XA CN114780173B (zh) 2022-01-25 2022-01-25 一种在应用中加载插件的方法、计算设备及存储介质

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
CN202210083574.4A CN114138376B (zh) 2022-01-25 2022-01-25 一种在应用中加载插件的方法、计算设备及存储介质

Related Child Applications (1)

Application Number Title Priority Date Filing Date
CN202210431692.XA Division CN114780173B (zh) 2022-01-25 2022-01-25 一种在应用中加载插件的方法、计算设备及存储介质

Publications (2)

Publication Number Publication Date
CN114138376A CN114138376A (zh) 2022-03-04
CN114138376B true CN114138376B (zh) 2022-06-24

Family

ID=80381556

Family Applications (2)

Application Number Title Priority Date Filing Date
CN202210083574.4A Active CN114138376B (zh) 2022-01-25 2022-01-25 一种在应用中加载插件的方法、计算设备及存储介质
CN202210431692.XA Active CN114780173B (zh) 2022-01-25 2022-01-25 一种在应用中加载插件的方法、计算设备及存储介质

Family Applications After (1)

Application Number Title Priority Date Filing Date
CN202210431692.XA Active CN114780173B (zh) 2022-01-25 2022-01-25 一种在应用中加载插件的方法、计算设备及存储介质

Country Status (1)

Country Link
CN (2) CN114138376B (zh)

Cited By (1)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN114780173A (zh) * 2022-01-25 2022-07-22 统信软件技术有限公司 一种在应用中加载插件的方法、计算设备及存储介质

Family Cites Families (11)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
WO2014159943A2 (en) * 2013-03-14 2014-10-02 Bitvore Corp. Dynamically loaded plugin architecture
CN106325921B (zh) * 2016-08-16 2020-07-10 北京奇虎科技有限公司 关联插件的释放方法及装置
CN106354832B (zh) * 2016-08-31 2020-09-25 广州品唯软件有限公司 一种数据发布方法、设备及系统
US10430208B2 (en) * 2017-05-02 2019-10-01 Huawei Technologies Co., Ltd. Multi-version asynchronous dynamic software update system and method for applications with multiple threads
CN108197020A (zh) * 2017-12-28 2018-06-22 掌阅科技股份有限公司 插件校验方法、电子设备及计算机存储介质
CN110134457A (zh) * 2019-04-17 2019-08-16 深圳壹账通智能科技有限公司 插件加载方法和装置
CN111857860A (zh) * 2019-04-30 2020-10-30 烽火通信科技股份有限公司 一种安全加载插件的实现方法及系统
US20200379781A1 (en) * 2019-05-28 2020-12-03 Netapp, Inc. Methods and systems for plugin development in a networked computing environment
CN112667306A (zh) * 2019-10-15 2021-04-16 华为终端有限公司 安装插件的方法、装置和存储介质
CN113760313A (zh) * 2020-06-05 2021-12-07 中兴通讯股份有限公司 云平台的升级方法、装置、设备、云平台系统及存储介质
CN114138376B (zh) * 2022-01-25 2022-06-24 统信软件技术有限公司 一种在应用中加载插件的方法、计算设备及存储介质

Cited By (2)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN114780173A (zh) * 2022-01-25 2022-07-22 统信软件技术有限公司 一种在应用中加载插件的方法、计算设备及存储介质
CN114780173B (zh) * 2022-01-25 2023-12-05 统信软件技术有限公司 一种在应用中加载插件的方法、计算设备及存储介质

Also Published As

Publication number Publication date
CN114780173A (zh) 2022-07-22
CN114138376A (zh) 2022-03-04
CN114780173B (zh) 2023-12-05

Similar Documents

Publication Publication Date Title
US11853774B2 (en) Dynamically loaded plugin architecture
US9183007B2 (en) Dynamic determination of application server runtime classloading
US8266588B2 (en) Creating projects in a rational application developer workspace
US7409675B2 (en) Code rewriting
KR20150024842A (ko) 적응식 이식가능 라이브러리
US9459986B2 (en) Automatic generation of analysis-equivalent application constructs
CN102364433B (zh) 在ARM处理器上实现Wine构建工具移植的方法
CN114138376B (zh) 一种在应用中加载插件的方法、计算设备及存储介质
US7987457B2 (en) Targeted patching for native generation images
US10747514B2 (en) Reduced save and restore instructions for call-clobbered registers
Cherubin et al. libVersioningCompiler: An easy-to-use library for dynamic generation and invocation of multiple code versions
US8769498B2 (en) Warning of register and storage area assignment errors
CN109558121A (zh) 接口驱动程序的开发方法、装置、设备及存储介质
CN112685040A (zh) 安卓系统中界面文件的生成方法、装置、设备及存储介质
CN111984300A (zh) 代码复制方法及装置、电子设备和计算机可读存储介质
US9672020B2 (en) Selectively loading precompiled header(s) and/or portion(s) thereof
CN113805971B (zh) 一种应用程序运行方法、计算设备及存储介质
WO2011157105A2 (zh) 组件扩展方法和装置
US20180196652A1 (en) Linker rewriting to eliminate toc pointer references
WO2021093442A1 (zh) 一种边缘辅助部署第三方应用到微控制器方法及系统
JP2009501385A (ja) ノード間通信パイプライン
CN111949301B (zh) 应用程序热更新方法、装置和计算机可读存储介质
WO2024036517A1 (zh) 一种交叉链接方法、装置,电子设备及存储介质
AU2016100581A4 (en) Compilation method for linking region-specific computer logic
CN114253615B (zh) 一种引导程序设置方法、装置、电子设备及存储介质

Legal Events

Date Code Title Description
PB01 Publication
PB01 Publication
SE01 Entry into force of request for substantive examination
SE01 Entry into force of request for substantive examination
GR01 Patent grant
GR01 Patent grant