杯具带来的教训-关于C和C++代码的混合链接

2012年8月29日 sigma 4 条评论 199,870 views

====我是分割线,只是想说明下面的都是废话,大家可以直接跳到下一个分割线====

这几天需要把Parsec(普林斯顿出品的一组多程序程序benchmark,C++编写,貌似是鼎鼎有名的李凯教授带的组出的)的一些程序移植到某模拟器上,由于模拟器没有OS,很多系统调用都是用硬件模拟。因此,parsec的pthread库需要替换成硬件提供的系统调用。在该模拟器上,之前已经有用汇编代码写好的系统调用库以及编程成了相应的静态链接库 .a文件。因此,理论上,只需要换掉pthread头文件,换成.a对应的头文件,并把对应的pthread函数换成硬件模拟的系统调用函数即可。

花了好大力气把所有的头文件以及pthread函数换掉,并且把Makefile的编译器换成交叉编译器,LDFLAGS里的多线程库换成了模拟器系统调用的.a库(通过 -Ldir -llib 替换,其中dir是.a文件所在目录,lib是.a文件的文件名去掉前缀lib和后缀.a的剩余部分)。一切就绪,敲下make,看着一个个.cpp变成了.o,我心里暗喜。可是,当所有.cpp变成.o后,杯具出现了,屏幕刷出一堆“undefined reference to xxxx”,其中xxx就是模拟器系统调用函数名。

奇了怪了,怎么会找不到reference呢,我第一感觉是LDFLAGS写错了,可是检查了几遍,发现没错。并且用同样的LDFLAGS链接splash2中的FFT程序都可以。因此,不太可能试着问题,并且为了确认,我加了-v选项,把链接的细节打出来了,发现没有任何问题。

排除了一种可能,但是问题并没有解决,我只好放狗搜。搜到的答案都是说由于库的链接顺序,会导致这问题,并且通假如某参数,链接时进行repeat搜索,可以避免该问题(当然,repeat的代码就是降低链接速度)。于是,我遍历了各种影响链接顺序的可能,包括LDFLAGS本身的顺序,以及源代码中包含头文件的顺序,可是,杯具依然。

两天过去了。。。还是一无所获,期间只好跑去机房调另外一个东西。昨天,在走投无路的情况下,狠下决心,用c语言重写parsec的这个benchmark。但是,决心容易下,真写谈何容易,看了半天,才把算法大致看明白。再看代码的过程中,我突然想,要不直接把模拟器的系统调用的汇编码嵌入到源代码中,不用.a形式静态链接,但是,由于这些汇编码的寄存器都是按mips标准命名用的,直接放进去,可能交叉编译器无法识别。于是,只好作罢,这时,突然想,为什么FFT可以,这个不可以,莫非是因为C++和C语言链接的方式不一样。想到这,突然有种豁然开朗的感觉,因为模模糊糊记得C函数的符号表和C++函数的符号表是不一致的。

====杯具终于完了,废话也终于完了,下面进入正题,貌似有点头重脚轻的感觉====

在c语言中,全局函数foo(int)在符号表中是_foo,而c++中,为了支持函数重载,会编译成类似_foo_int的。这就导致了前述xxx的系统调用会编译成_xxx_yyy(yyy是参数类型)的形式存在.o中。难怪链接器会找不到reference。

因此,下一步就是如何让C++代码能链接到c代码中了。于是继续放狗搜“c c++ link”,搜到了伟大的太阳的这篇文章:

Mixing C and C++ Code in the Same Program

这篇文章说道,其实可以通过extern关键词声明函数是c函数还是c++函数。当然,也可以直接extern某个头文件,将整个头文件里的函数都声明是啥函数。比如,下面代码:

extern "C" {
  #include "sb.h"
}

就降sb.h 里面的函数都声明是c函数。这样,在c ++代码中,碰到sb.h中的函数,就会当成c函数来对待。

对于我碰到的问题,可以前述extern 头文件来解决。但是,对于大部分头文件来说,我们并不知道这个头文件里的函数是c函数还是c++函数。这就要求头文件编写者做些工作,一般来说,现在的系统库里面都能看到下面的语句:

#ifdef __cplusplus
extern "C"{
#endif

//some function declaration 

#ifdef __cplusplus
             }
#endif

上面的代码就是为了让库兼容c和c++.因为使用g++编译器的时候,实际上是带了__cplusplus的声明,因此整个头文件的函数都会被额外的声明是c函数。之后g++会特殊处理,从而保证链接不出错。

最后,再说几句废话,博客荒废已久,本来以为八月必然交白卷的,想不到最后还是憋出来一篇。。。

分类: 贝壳 标签: , ,

#照片#英伦行

2012年7月15日 sigma 7 条评论 18,500 views

六月下旬,去曾经的日不落开了个会,在这里传些照片,给之前跟我说想看照片的一些同学看看,顺便凑篇博客。

imageimage 阅读全文…

分类: life 标签:

五月流水账(多图杀猫慎入)

2012年5月31日 sigma 2 条评论 12,028 views

转眼五月就过去了,才发现在五月,我只写了一篇博文。其实中间几次想写,无奈江郎才尽,无从下笔。到了月末,逼着自己写一篇,尽管是流水账,顺便测试下wordpress手机客户端。无奈写流水账都写不好,只好用图片来凑个流水账。废话完了,上图:

image

我们的计算所

阅读全文…

分类: life 标签:

pdf嵌入字体

2012年5月12日 sigma 4 条评论 25,421 views

在论文提交final script时,一般都要求论文中所有的字体都嵌入到pdf中,一般来说,IEEE提供了一个叫做EXPRESS的工具,可以检查是否符合规范,包括字体是否嵌入。但是,有时候,我们通过latex编译出来的pdf,不能通过EXPRESS检查,并且大部分都是因为字体原因,那么,本文将介绍如何在linux pdflatex编译时能够潜入所有字体。

首先,linux下本身提供了一个检查pdf字体信息的工具,pdffonts。比如查看test.pdf的字体:

pdffonts test.pdf

结果应该是类似下面的:

name                                 type              emb sub uni object ID
------------------------------------ ----------------- --- --- --- ---------
JNARJV+NimbusRomNo9L-Medi            Type 1            yes yes no       6  0
NBINYZ+NimbusRomNo9L-Regu            Type 1            yes yes no       7  0
CBDPEB+NimbusRomNo9L-ReguItal        Type 1            yes yes no       8  0
ZYBBWF+CMSY10                        Type 1            yes yes no       9  0
QVCFWU+NimbusRomNo9L-MediItal        Type 1            yes yes no      10  0
IJIDBD+CMMI10                        Type 1            yes yes no      11  0
MTWRTR+CMR10                         Type 1            yes yes no      16  0
Arial                                TrueType          no  no  no      35  0
Arial,Italic                         TrueType          no  no  no      36  0
WXQMOP+CMMIB10                       Type 1            yes yes no      46  0
Helvetica                            Type 1            no  no  no      51  0
DWKNIZ+CMMI7                         Type 1            yes yes no      55  0
IXNPPI+CMEX10                        Type 1            yes yes no      56  0
EUDIGL+CMR7                          Type 1            yes yes no      57  0
CLXNUD+CMSY7                         Type 1            yes yes no      58  0
RURLFQ+CMMIB7                        Type 1            yes yes no      62  0
LDBHLR+CMBX10                        Type 1            yes yes no      63  0
YJCSYX+CMMI5                         Type 1            yes yes no      69  0
Helvetica                            Type 1            no  no  no      74  0
Helvetica                            Type 1            no  no  no      79  0

可以看到,有些字体emb选项为no,表示没有嵌入。 阅读全文…

分类: 贝壳 标签: , , , ,

Vimdiff逐行比较

2012年4月27日 sigma 1 条评论 9,163 views

平时,我们用vimdiff都是基于最大匹配,但有时我们希望能够逐行比较,这个不能直接实现,但是可以通过diff的patchexpr实现,具体介绍可以看vim文档:

http://vimdoc.sourceforge.net/htmldoc/diff.html

下面给出一个vim逐行比较的patch,将下面内容复制到一个文件diffbyline.vim,并且放到plugin目录下(这个脚本是我很早从网络搜到的,现在忘了来源了,哪位看到来源,请告知,我好说明):

" File:         diffbyline.vim
" Created:      2010 Sep 28
" Last Change:  2010 Oct 02
" Rev Days:     3
" Author:	Andy Wokula <anwoku@yahoo.de>

" :SetLineByLineDiff[!]
"
"   set the 'diffexpr' to enable a trivial line-by-line diff algorithm (the
"   diff program has no option for this).  Reset 'diffexpr' with [!].

com! -bar -bang SetLineByLineDiff  call s:SetDiffExpr(<bang>0)

func! s:SetDiffExpr(bang)
    if !a:bang
	set diffexpr=DiffLineByLine()
	echo "'diffexpr' changed to enable line-by-line diff"
    else
	" XXX restore the previous value
	set diffexpr&
	echo "'diffexpr' restored"
    endif
endfunc

func! DiffLineByLine()
    let result = []	" diff output lines
    let oldlines = readfile(v:fname_in)
    let newlines = readfile(v:fname_new)

    let len_oldlines = len(oldlines)
    let len_newlines = len(newlines)
    let len_common = min([len_oldlines, len_newlines])

    " different number of lines allowed
    "	first common lines -> change(s) only
    "	rest -> append (er, no, see below)

    let idx = 0
    let change_start = -1
    while idx < len_common
	if oldlines[idx] !=# newlines[idx]
	    " XXX above test is case sensitive and ignores 'diffopt'
	    if change_start == -1
		let change_start = idx
	    endif
	    let change_end = idx
	elseif change_start >= 0
	    " line-idx is just after a block of changed lines

	    " prepare a diff block
	    if change_start < change_end
		let range = (1+change_start). ",". (1+change_end)
	    else
		let range = 1+change_start
	    endif
	    let ed_cmd = range. "c". range
	    call add(result, ed_cmd)
	    call extend(result, map(oldlines[change_start : change_end], '"< ". v:val'))
	    call add(result, '---')
	    call extend(result, map(newlines[change_start : change_end], '"> ". v:val'))

	    let change_start = -1
	endif
	let idx += 1
    endwhile

    if change_start >= 0

	" XXX extract to function? (paragraph copied from above)
	if change_start < change_end
	    let range = (1+change_start). ",". (1+change_end)
	else
	    let range = 1+change_start
	endif
	let ed_cmd = range. "c". range
	call add(result, ed_cmd)
	call extend(result, map(oldlines[change_start : change_end], '"< ". v:val'))
	call add(result, '---')
	call extend(result, map(newlines[change_start : change_end], '"> ". v:val'))

    endif

    if len_oldlines < len_newlines
        let append_start = len_oldlines
        let append_end = len_newlines - 1
        let old_range = append_start	" append below this line
        if append_start < append_end
            let new_range = (1+append_start). ",". (1+append_end)
        else
            let new_range = 1+append_start
        endif
        let ed_cmd = old_range. "a". new_range
        call add(result, ed_cmd)
        call extend(result, map(newlines[append_start : append_end], '"> ". v:val'))

    elseif len_oldlines > len_newlines
        let delete_start = len_newlines
        let delete_end = len_oldlines - 1
        let new_range = delete_start	" delete below this line
        if delete_start < delete_end
            let old_range = (1+delete_start). ",". (1+delete_end)
        else
            let old_range = 1+delete_start
        endif
        let ed_cmd = old_range. "d". new_range
        call add(result, ed_cmd)
        call extend(result, map(oldlines[delete_start : delete_end], '"< ". v:val'))

    endif

    " Decho result
    " XXX strange: :D echo prints at least two result lists, first is
    "	['1c1', '< line1', '---', '> line2'] and belongs nowhere (is this an
    "	internal diff test by Vim?)

    call writefile(result, v:fname_out)

endfunc

使用方法:

  • 在diff界面,输入:SetLineByLineDiff,跳到逐行模式,再输入一次,回到普通模式。
  • 或者加个SetLineByLineDiff选项,如:vimdiff +SetLineByLineDiff a.c b.c
分类: 贝壳 标签: , ,

无觅相关文章插件,快速提升流量