将函数私有化到C中的库中
我最近不得不面对一个关于lib管理的相当复杂的问题,但我会非常惊讶地发现自己是第一个 假设您正在C中创建一个名为将函数私有化到C中的库中,c,dll,shared-libraries,static-libraries,C,Dll,Shared Libraries,Static Libraries,我最近不得不面对一个关于lib管理的相当复杂的问题,但我会非常惊讶地发现自己是第一个 假设您正在C中创建一个名为lib1的库(静态或动态)。lib1中的lib1是一些通过API公开的函数,以及一些其他保持私有的函数 理想情况下,私有函数应该是静态的。不幸的是,让我们假设一个名为extmod.c的源文件来自另一个项目,保持它不被修改是有益的。因此,对它定义的函数进行静态是不现实的 因此,在extmod中定义的所有函数都存在于lib1ABI中,但不存在于API中,因为相关的*.h未发货。所以没人注意
lib1
的库(静态或动态)。lib1中的lib1
是一些通过API公开的函数,以及一些其他保持私有的函数
理想情况下,私有函数应该是静态的。不幸的是,让我们假设一个名为extmod.c
的源文件来自另一个项目,保持它不被修改是有益的。因此,对它定义的函数进行静态是不现实的
因此,在extmod
中定义的所有函数都存在于lib1
ABI中,但不存在于API中,因为相关的*.h
未发货。所以没人注意到
不幸的是,在后期,有人想链接lib1
和另一个lib2
,其中还包括extmod
。由于定义重复,因此会导致链接错误
在C++
中,这个问题的答案是一个简单的名称空间。在C语言中,我们就不那么幸运了
这个问题有几种解决方案,但我想探讨一下,是否有人认为已经找到了一种有效的、非侵入性的方法。所谓“非侵入性”,我指的是一种方法,如果可能,它可以避免修改extmod.c
在可能的解决方法中,可以使用不同的前缀更改extmod.c
中的所有定义,从而有效地模拟名称空间。或者可以将extmod.c
的内容放入extmod.h
中,并对所有内容进行静态处理。这两种方法都广泛地修改了extmod,尽管
请注意,我已经看过了,但它没有解决这个具体问题。您可以通过从构建中排除extmod.c,而将其作为头文件来实现“不同前缀”解决方案。使用C预处理器可以有效地修改文件,而无需实际修改它。例如,如果extmod.c包含:
void print_hello()
{
printf("hello!");
}
从构建中排除此文件,并添加一个名为ns_extmod.c的文件。此文件的内容应如下所示:
#define print_hello ns_print_hello
#include "extmod.c"
编译时,C预处理器将print_hello重命名为ns_print_hello,但原始文件将保持不变
或者,如果且仅当extmod.c未在内部调用该函数时,可以使用预处理器以相同的方式使其成为静态的:
#define print_hello static print_hello
#include "extmod.c"
假设您可以控制构建过程,这对您来说应该是可行的。在不实际编辑extmod.c的情况下进行前缀的一种方法如下:
创建一个新的头文件extmod_prefix.h,如下所示:
#ifndef EXTMOD_PREFIX_H
#define EXTMOD_PREFIX_H
#ifdef LIB1
#define PREFIX lib1_
#else
#ifdef LIB2
#define PREFIX lib2_
#endif
#endif
#define function_in_extmod PREFIX##function_in_extmod
/* Do this for all the functions in extmod.c */
#endif
在extmod.h中包含此文件,并在LIB1的构建过程中定义LIB1,在LIB2中定义LIB2
这样,extmod.c中的所有函数都将以lib1中的lib1和lib2中的lib2作为前缀。(以问题的形式)。有关部分:
objcopy——前缀符号
允许我为由导出的所有符号添加前缀
对象文件/静态库
你真的不需要手动修改文件,我的意思是不需要逐个函数,我会使用libclang
可能是python绑定,并从extmod.c
的源代码创建一个新文件,其中所有函数都是静态的。这并不是那么简单。如果extmod.c
中的函数被盲目地设置为静态,那么即使是库也无法访问它们。因此,它需要额外的转换,比如将.c
的内容转换为.h
,这样您就开始继承更多的问题,比如命名冲突、未使用的静态代码等等……好吧,我正试图完全理解您的建议,因为它似乎走上了正轨。特别是我喜欢它似乎不需要修改初始文件。现在让我们假设我们有一个文件ns\u extmod\u c
,正如您所建议的,它包含一组宏翻译的符号名,然后包括extmod.c
。我猜类似的转换也必须应用于extmod.h
文件,以便原型定义一致。您最后一次对static
的评论对我来说不太清楚……好吧,再想想,最好在.h
级别引入翻译宏。由于包含了.h
,定义将自动传输到.c
。更好的是,调用包含.h
的程序也可以免费获得翻译的好处,因此也无需更改代码的这一面。看来各方都赢了。现在开始练习……好吧,如果我们也不想接触.h
,那么有必要定义ns\u extmod.c
和ns\u extmod.h
,它们将成为用户程序调用的版本。另一个想法类似于@harshad:翻译后的符号名称被转换成extmod.h
中包含的.h
,所有新名称都会自动传输。但它需要在extmod.h
中更改一行代码。如果你问我,这没什么大不了的,但是在以后的更新中很容易犯错误:不将extmod.h
修改为。\include“ns_extmod.h”
会导致使用原始名称,从而产生名称冲突。最后一条关于将其设置为静态的评论没有多大意义,但我认为你现在走在正确的轨道上了!:-)这是一个非常好的主意。最后,我还是更喜欢@Shwany方法,它与您建议的方法非常接近。主要区别在于,用户程序包括备用ns_extmod.h
,并编译备用ns_extmod.c
,而不是原始程序。主要的好处是长期的:在未来很长一段时间内,有人会