将函数私有化到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未发货。所以没人注意

我最近不得不面对一个关于lib管理的相当复杂的问题,但我会非常惊讶地发现自己是第一个

假设您正在C中创建一个名为
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
,而不是原始程序。主要的好处是长期的:在未来很长一段时间内,有人会