zoukankan      html  css  js  c++  java
  • 提高Delphi的编译速度(bpl和bcp)

    delphi的编译速度提高(一)

    此博文为原创,转载请注明出处

    作者 :二娃

     

    此博文的内容我曾经回答群内和论坛内的网友提问时回答过,现在写第一部分,第二部分,我再给出一个终极的提高速度的方法

    我用过delphi 7,delphi2005,2006,2007 现在零星地用用2009以及2010,但是无论用哪种版本,其中第三方控件是少不了的,可是随之而来的问题是,每多用一种类型的第三方控件,delphi的编辑和代码提示速度降低一些,到最后,像代码提示(实际上也是编译或者预编译)有时弹出提示内容竟要花去1分钟,急得直让人吐血

    我现在将这种慢的地方例出来:

    1.              编译时,Ctrl+F9或者F9,delphi将所有用到的单元pas编译成dcu中间文件,再将dcu组后成可执行文件(exe,dll,bpl)

    2.              首次代码提示第1种情况后的首次代码提示,将此单元内的直接引用或间接引用到的其它单元统统编译成dcu存于内存或者解析dcu的内容存于内存,当编译再次编辑时,delphi先清除dcu解析缓存,从头再来.

    3.              以上两种的慢慢的地方,主要是解析dcu文件开销,第二次代码提示则不需要,因为缓存内已经有解析好的dcu

    要了解决上面的问题我先延伸出一个解释出来

    bcp文件是bpl文件生成时的付产品,对于执行文件来说是没有什么用的,但是对于delphi作用可是少不得,是不可或缺的。bpl和dcp都是为都可以被delphi调用,但是调用的方式是不一样的。

    bpl文件是执行调用:delphi(包括其它的exe)执行时直接访问bpl的地址,如果地址不存在,就会报错.

    bcp文件是编译调用:delphi在编译时不访问引用的bpl的,访问的信息来自相应的dcp,,同一时期编译出来的dcp文件总是正确地记录相关bpl的地址,供delphi编译时通过.delphi编译执行文件时,不会检查bpl与bcp的版本是否一致,它只管读到bcp,因此不管相应bpl有无直正的地址即使bpl不存,dcp说有什么,在什么位置,delphi就完全相应它,编译通过,假如dcp文件没有相关地址信息,即使相应的bpl有,编译也通不过.

    打个比方,bpl好像一个产品,提供特定的功能,dcp文件就好像bpl的产品说明书,delphi编译时就相当于生产,按说明书生产另一个配套产品(exe,dll,bpl), delphi调用bpl时就像把bpl组装到exe.dll上,由于exe,dll是根据说明书上生产来的,它就认为被组装的bpl一定有相关的结口,此时如果产品接口,型号不对,当然不能组装了

           好了,理解了上面,我们可以这样解释:delphi编译文件时(提示框弹出也是一种编译,前面说过),先要准备说明书,如果说明书没有,就现场制作(解析dcu,如果没有dcu文件,就要从pas文件转换成dcp),慢就慢制作说明书这个过程,假如先把说明书提供给delphi,那么delphi就会再花上一段时间造说明书了,这段时间就会被节省下来,很简单,提供相关单元的bpl的dcp文件给它,那怎么提供呢?

    打开工程:Project->Options->Packages->Build with runtime packages 钩上,

    这样我们在写代码时,或者编译测试时,速度就会大大提高,原来要1分钟时间才弹出提示,现在还不1秒中.快了很多吧?

    等到产品最要终于给用户时,再将Build with runtime packages 钩去掉,再编译一个完整的exe 给用户,这样就可以不带bpl了

       如果不想去掉钩,就要把相应的bpl提示给用户,刚才说到的钩内的框内有很多说明书,但不是每种bpl对于最终用户使用exe都是必需的,我的经验是按我使用的控件,先大体把相应的bpl代到,一起考备到一个干净的机器上,然后运行exe,提示缺哪个再考哪个,

    我倾向于后面一种文法,给相关的bpl,但是又会有一个问题来了,我在

    《Delphi打包bpl暨delphi的编译速度提高(二)》中接着讲
    Delphi打包bpl暨delphi的编译速度提高(二)

    此博文为原创,转载请注明出处

    作者 :二娃

    在(一)种我讲到利用dcp文件提高delphi编译及代码提示速度的方法,最后抛出一个问题.

    什么问题呢?假如我的工程是引用包编译的,那么就必需要提相应的bpl给用户,视程序用到的控件种类而定,从几个到几十个不等,这样就有一个效率的问题,比如只用到一个控件包中的一个控件,那么我也提供这组控件的完整的bpl包,那就显得太浪费,不是吗?毕竟你不是M$,每个产品发布时都要用DVD来,

    exe文件小看起来漂亮,编译也快,也许我是一个完美主意者才这样说的.

    如果你用过skype,在这里我给广大delphi爱好者打打气,skype是delphi写的,卖了43亿$,神吧?佩服吧?但我不喜欢skype编译出来的文件或者打包方式,skype提供给用户的就一个exe(08年时是14M多),我想编译skype的人一定很有恒心,14M呢,每次调试时都要花半天才能编译出来,写代码时,代码提示也是个问题。

    如果有方法把exe内用到的所有控件单元单独打包成一个bpl或少量若干个bpl再加上一个exe文件,那这就太完美了,有没有方法呢?有,把程序本身的引用到单元单独提出来,至于间接引用到的单元可以不用管,单独制作一个bpl(dcp也一样)编译输入到exe存放的目录下,编译这个bpl时,delphi提示此bpl是否要此用到其它的bpl,要千万不要引用,否则就白做了. Project->Options->Packages->Build with runtime packages 钩上,在包内就加上你刚才的bpl名称(不带.后面的),OK了.

    这样只有当我改动第三方代码时,我才要重新编译bpl,否则的话,这块的编译永远省略,速度那提高得没话说.

    我自已制作了一个这样的ide工具,是从cnwizars基础上写的,用于自动查找工程或工程组中引用的单元,再将这些单元制作成bpl,但是由于tree的那部分用到商业控件,所以不能发布,等我有空件时改成免费控件时,再发布给相要的人使用.

    用上面的方法,无论手动或自动制作的bpl,看上去很美,用起来也呱呱叫,但是紧接着问题就来了。那就是多线程的问题。网上有人提问过,我实际中也遇到过,

    线程在bpl文件内使会时不时地出问题,而且出现的问题没有有规律,无法测试跟踪或者太难测试,原因当然不只是vcl控件不是线程安全的这一个原因这样简单。在bpl内,线程的waitfor等线程方法会无限制地等下去.程序也许可以启动,但退不出来,等等,我个人的理解bpl 还不是真正意义上的dll,在dll内Hintance有真正的实例,bpl则不是.所以线程退不出来。线程在地址上读写冲突.比如,loadbpl时,线程就开始工作,可是这时实例还没有创建....

    线程不能在bpl内运行,或者运行不好,那有没有一种方法将线程提到bpl外运行呢.我之前的方法是将含有线程的代码不引用到bpl内,一个个单元区分,甚至改大量地改动第三控件的代码,但是随着使用深入,发现这种方法也太不现实,有时改动的第三方代码太多,再遇到含有线程的控件如果是基类的话,那区分的地方就更多了,经过我多次实验,我终于发现,只要线程的实例的创建不要由bpl内的代码直接创建就行,间接创建就不会有问题,经过多次的实践,最终证实是这样的, 明白了这个,那只需要稍微地改动一个第三方代码,问题就好办多了。下面简单举个例子

    某bpl内单元种有一段创建线程的实例的地方:

    (终极解决方法)

    Unit Unitbpl

    Interface

    Use

    …….

    Implementation

    procedure Createxxxthread;

    begin

    ….

    fxxxthread:= Txxxthread.create(someparams);

    …..

    end;

    end.


    我现在将上面的单元稍微改动成以下

    Unit Unitbpl

    Interface

    Use

    …….

    TCreateThreadFun=Function(Somparms): Txxxthread;

    Var

    _CreateThreadFun: TCreateThreadFun=nil;

    Implementation

    procedure Createxxxthread;

    begin

    ….

    if @_CreateThreadFun<>nil then

    fxxxthread:=_CreateThreadFun(someparams);

    …..

    end;

    end.

     


    接着我再写一个单元

    Unit CreateThreadUnit

    Interface

    Use

    Unitbpl;

    Implementation

    Function newCreateThreadFun(someparams): Txxxthread;

    Begin

    result:=Txxxthread.create(someparams);//线程实例在exe内创建

    End;

    Initialization

    @ CreateThreadFun:= newCreateThreadFun //初始化时,这里填写地址

    Finalization

    @ CreateThreadFun:=nil; //也可以不要这一行

    End.


    //注意此单元直接此用到exe工程中引用了,千万不能放在bpl内,

    以上方法经过千万的试验,线程没有任何问题。

    http://www.vckbase.com/module/articleContent.php?id=4372

  • 相关阅读:
    【Codechef】Chef and Bike(二维多项式插值)
    USACO 完结的一些感想
    USACO 6.5 Checker Challenge
    USACO 6.5 The Clocks
    USACO 6.5 Betsy's Tour (插头dp)
    USACO 6.5 Closed Fences
    USACO 6.4 Electric Fences
    USACO 6.5 All Latin Squares
    USACO 6.4 The Primes
    USACO 6.4 Wisconsin Squares
  • 原文地址:https://www.cnblogs.com/findumars/p/5624891.html
Copyright © 2011-2022 走看看