静态库制作——以greenhills举例
使用GHS软件创建
默认背景是已经有完整可编译的工程,只是需要将其中一部分打包成.a库
1.新建library工程
会出现默认的两个子工程,通过右键查看其default.gpj可知。我根据需要保留了library的工程
2.添加自己的source文件,此处我还将默认的ld文件修改程了自己的
3.到此为止,如果头文件路径、编译config已经定好,那可以直接编译了
生成的文件在根目录下,当然也可以自己指定
4.另外新建工程包含我们的a文件,用.a文件替换掉源文件,源工程的其他.a保留
新工程需要包含头文件,不然怎么找到调用的函数,因此如果想尽可能少的暴露文件,最好自己再封装一层
如果.a中调用了需要新工程中补充完整的函数,那么实际使用的工程需要先编译被用到的c文件,之后链接时才不会出现symbol未找到的错误
使用SCons脚本创建
关于SCons不再介绍,我感觉就是用python的Makefile,但是命令执行顺序是SCons自己决定的,而非编写时的顺序。
其实静态库就是一个将.o打包的过程,如果是在linux服务器上,只需ar x lib.a ./
,就能把这个lib解包成一堆.o,ar r lib.a ./*.o
,就又能打包出来,ar -d lib.a del.o
是删除,ar -r lib.a add.o
是加入。
说回生成静态库,SCons的文档里给出了方法:Library() / env.Library(),网上的方法也大多使用这个,但是举例时只有几个文件,但是在实际项目中使用时,少则上千个文件,我在使用时,link成.a的时候cmd报错“文件名或拓展名过长”。
因为在实际使用时,我们会先把所有的c编译成.o,然后把object传给Library():
# 在SConstruct中
object = []
object += SConscript(target_path, exports='env', variant_dir=target_dir, duplicate=0)
lib = env.Library(output_path, object)
如果我们在scons_common.py中,打印出link时用的指令,就会发现在最后会把所有的.o名字、路径都传进去,导致要执行一条巨长的命令。
因此,在SCons里重定义一个builder,指令中的源文件(.o)列表以宏形式传入:
env['LIBSOURCE'] = ''
env['LIBCOM'] = 'D:\GreenHS\202115\ccarm.exe -archive -o yourname.a -cpu=$TARGETCPUOPT $LIBSOURCE'
env['BUILDERS']['MakeLib'] = = SCons.Builder.Builder(action = '$LIBCOM',suffix = env.subst('.a'))
然后在SConstruct中生成这个列表并加入env的宏:
def gen_file_list(fname,flist):
with open(fname,'w') as fdoc:
for f in flist:
fdoc.write('%s\n' % os.path.relpath(str(f).replace('\\','/')))
fdoc.close()
return fname
object = []
object += SConscript(target_path, exports='env', variant_dir=target_dir, duplicate=0)
rsp_file = gen_file_list('libsite.lst', object)
env.Append(LIBSOURCE= ' @%s' % os.path.relpath(rsp_file))
lib_exe = env.MakeLib(output_path, object)
有一点奇怪的是不知道是工程原因还是命令,.a中有一些weak函数的声明并没有生效,导致有些函数错误的执行了弱函数,目前的解决办法就是在libsite.lst里删掉正常函数所在.c生成的.o,然后额外包含这个.o,这样.o里的函数能正常链接到,不去执行weak函数。