现在的位置: 首页 > 综合 > 正文

WinCE的Sources文件中TargetLibs和SourcesLibs的作用与区别

2013年06月04日 ⁄ 综合 ⁄ 共 4884字 ⁄ 字号 评论关闭

在WinCE里面,编译和链接的必备文件sources,做过WinCE BSP开发的一定都很熟悉,其中有2个关键字,targetlibs和sourcelibs,一直让我对其中的区别很感兴趣,故查阅了一些资料,与大家分享
    其实只要搜索以下就会得到一些基本的答案,比如:

TARGETLIBS,如果一个库以DLL的形式提供给调用者,就需要用TARGETLIBS,它只链接一个函数地址系统执行时会将被链接的库加载。比如coredll.lib就是这样的库文件。即动态链接。

SOURCELIBS,将库中的函数实体链接进来。即静态链接,用到的函数会在我们的文件中形成一份拷贝。

这个答案已经基本解决问题了,但是这个答案让我们能看到更深入的东西:
This is componentization feature of Windows CE.
The link has two steps. First, whatever is in SOURCELIBS gets combined in a
signle library yourproductname_ALL.lib. In the second step, executable
module is linked from that library and all the targetlibs.
This is done to allow stubs to be conditionally linked: if the function is
defined into your source already, stubs get excluded. If it is not there,
stubbed version (returning ERROR_NOT_IMPLEMENTED or something to that
effect) gets linked in instead.
If the link were to be performed in just one step, it would be impossible to
predict which version (real or stub) would get included. As it is,
implemented functions have a priority over stubs.
--
Sergey Solyanik
Windows CE Core OS

总的来说就是先编译了你自己在sources里指定的源文件,在链接阶段,先将所有的sourcelibs链接在一起成为一个lib,然后与targetlibs指定的lib一起参与链接。

当然这里targetlibs指定的可以是dll的lib文件,在CE的帮助文件中,有说明targetlibs可以使用import libraries or static libraries。但是sourcelibs说明中指出一般用在把许多小的lib合并为一个大的lib。

还有关于用法的一些说明:

EXEs
    Only TARGETLIBS get linked, anything in SOURCELIBS is ignored
DLLs
    SOURCELIBS and TARGETLIBS get linked, in that order
LIBs
    Only SOURCELIBS get linked, anything in TARGETLIBS is ignored

Google groups 上Steve Maillet一直在回答相关的问题,并且强调只是一些link的顺序问题,可以参看makefile.def。

为了把问题弄清楚,看了下makefile.def因为很少接触makefile文件,所以凭有限的makefile知识,来解读下(MS的全自动化编译工具害人啊)

注:由于对makefile了解有限,如果分析有错误的地方请大家指出

1. 关于LIBS的link

    !IF "$(TARGETTYPE)" == "LIBRARY"
    $(_RELEASELIBDIR)/$(TARGETNAME).lib: $(TARGETOBJFILES) $(SOURCELIBS)
    @echo BUILD_MARKER:LINK_STATIC_LIBRARY_START Linking $@
    $(LIBRARIAN) -out:$(_RELEASELIBDIR)/$(TARGETNAME).lib $(MACHINEOPTION) @<<
    -ignore:4001
    $(LIBDEFINES)
    -nologo
    -nodefaultlib
    $(LINKER_SUBSYSTEM)
    $(TARGETOBJFILES)
    $(SOURCELIBS)
    <<NOKEEP

    可以看出,是忽略了TARGETLIBS的东西

2. 关于DLL
    有些条件判断,但是链接顺序都是
    $(TARGETOBJFILES)
    $(SOURCELIBS)
    $(TARGETLIBS)

3. 关于EXE
    $(TARGETOBJFILES)
    $(TARGETLIBS)
    $(SOURCELIBS)

由此对
EXEs
    Only TARGETLIBS get linked, anything in SOURCELIBS is ignored
产生了一些质疑

关于链接顺序:

    在我的印象里,应该是出现同样的symbol,优先链接第一个出现的(查了半天也没有找到文档作为证明,不过我用bcc试了一下,默认是链接第一个出现的)。

    这样就说明了链接顺序带来的影响,比如你的源文件里有一个func这个函数的实现,但是在sourcelibs里包含的func1.lib里面也有同样函数的实现,这时候会使用你的源文件里面的func实现,而不是func1.lib里面的,同样对应于targetlibs

    这样做可以使用一些stub,比如KITL.c在BSP的两个地方实现Src/Kernel/Kern和Src/Kernel/Oal,而kern下的就是个stub,里面什么也没做,用来关闭KITL功能,OAL下的才是功能实体,在链接过程中,kern下使用TARGETLIBS来引入oal.lib,但是OAL下KITL.c里面的函数实现都已经被kern下的KITL.c替换了,这个生成的kern.exe后续会在common.bib里面被加入NK.exe(关闭KITL的时候)。而Src/Kernel/Kernkitl下生成的kernkitl.exe也引入了oal.lib,由于自身没有KITL的实现函数,所以实现代码就是OAL里面的代码,在打开KITL的时候就会加入NK.exe。

    以下是common.bib的关于KITL的片断:

    IF IMGNOKITL
       nk.exe          $(_FLATRELEASEDIR)/kern.exe                 NK  SHXL
    ENDIF IMGNOKITL
    IF IMGNOKITL !
       nk.exe          $(_FLATRELEASEDIR)/kernkitl.exe             NK  SHXL
    ENDIF IMGNOKITL !

这里也就说明了KITL开关的原理(build层面的关闭)

从上面的说明,我们是否可以得到以下结论:

1. 对于LIBS,targetlibs是没有使用的, 对于DLL和EXE,只是链接顺序的不同

2. 在build DLL和EXE时需要小心相同函数的覆盖关系

 

 

 

 

>>出现同样的symbol,优先链接第一个出现的
如果链接阶段出现同名symbol,链接器难道不是应该报错吗?这应该是典型的链接问题。错误信息大致是:
xxx is already defined in yyy

 

根据boland c compiler的试验结果,是不会报错的,重复定义的错误一般是编译阶段的源文件中的宏定义重复

 

这明显是链接期的问题。比如在eboot的main.c中,我定义函数:
void test(){}
同时在eboot的另一个源文件utils.c中再定义一次:
void test(){}
链接时就会报错:
utils.obj : error LNK2005: test already defined in main.obj

 

sting兄提到的这个问题确实是这样,我也做了类似的验证
但是同样发现了一件事情,大概可以解释这些吧
如果你在eboot里面更改一个文件,定义一个重复的函数,确实会出现上面的问题
但是,我们在oal里面,同样更改一个文件,重复定义一个函数,发现就不是错误了,而是一个警告,也不会当作错误处理
BUILD: [01:0000000024:WARNN ] oal_startup.obj : warning LNK4006: OALInitSysCtrl already defined in pmic.obj; second definition ignored

BUILD: [01:0000000025:INFO  ] Stop.

BUILD: [00:0000000026:PROGC ] Done.
BUILD: [00:0000000027:PROGC ]                      Files      Warnings      Errors
BUILD: [00:0000000028:PROGC ] Midl                     0             0           0
BUILD: [00:0000000029:PROGC ] Resource                 0             0           0
BUILD: [00:0000000030:PROGC ] Message                  0             0           0
BUILD: [00:0000000031:PROGC ] Precomp Header           0             0           0
BUILD: [00:0000000032:PROGC ] C/Cpp/Cxx                1             0           0
BUILD: [00:0000000033:PROGC ] Assembler                0             0           0
BUILD: [00:0000000034:PROGC ] Static Libraries         1             1           0
BUILD: [00:0000000035:PROGC ] Dll's                    0             0           0
BUILD: [00:0000000036:PROGC ] Exe's                    0             0           0
BUILD: [00:0000000037:PROGC ] Resx                     0             0           0
BUILD: [00:0000000038:PROGC ] Csharp Targets           0             0           0
BUILD: [00:0000000039:PROGC ] Other                    0             0           0
BUILD: [00:0000000040:PROGC ]
BUILD: [00:0000000041:PROGC ] Total                    2             1           0
BUILD: [00:0000000042:PROGC ]
BUILD: [00:0000000043:PROGC ] 1 Warnings,  0 Errors

编译通过,没有问题

然而oal生成的是lib文件,就是说在链接lib文件的时候,出现重复的函数,默认用第一个,我不知道有没有参数可以设置

但是这个规则似乎在exe就不行了,就会出现上面的错误

但是关于文章里提到的KITL的问题,生成的是kern.exe为什么没有错误呢?
原因就是重名的那个函数是在lib里面的,而不是obj文件
如果是另一个需要编译的文件里面有重复函数,也是会出现上面错误的
而用lib或dll都不会出现这个问题,甚至连警告都没有

我想这个应该是链接器做的动作,具体的原因还没有深入研究,可能与特定链接器有关

抱歉!评论已关闭.