【问题标题】:Self-Contained C Shared Library自包含的 C 共享库
【发布时间】:2015-05-15 18:36:37
【问题描述】:

我目前正在为客户开发一个 C 库,为此我需要使用其他库,例如:glib2.0、libxml2、lib、openssl 和 gmp。在我完成开发并创建 .so 后,我尝试用它编译一个测试程序,发现我的库不是独立的,我需要将程序与我上面提到的所有其他库链接。

客户坚持他想要一个 dll 或 .so 产品,并且它应该是自包含的,只有一个文件,以便他的应用程序可以使用它,就像他使用其他库一样。

我不知道该怎么办,有没有办法产生这个自包含的.so?如果不可能,我还有什么其他选择?我正在使用 Solaris 11 进行开发,目标系统是 Solaris 服务器。

非常感谢。

生成文件代码:

# C compiler 
CC = gcc 

# C flags
CFLAGS = -fPIC -O3 -g 

# linking flags
LDFLAGS = -shared 
LDLIBS = $(shell xml2-config --cflags --libs) $(shell pkg-config --cflags --libs glib-2.0) -lssl -lcrypto -lm -lgmp -lz 

# target lib
TARGET_LIB = libservices.so
SRCS = lib1.c lib2.c lib3.c lib4.c # source files

OBJS = $(SRCS:.c=.o)
# Compilation 
.PHONY: all
all: ${TARGET_LIB}

$(TARGET_LIB): $(OBJS) 
    ${CC} ${LDFLAGS} $(OBJS) -o ${TARGET_LIB}

# pull in dependency info for *existing* .o files
-include $(OBJS:.o=.d)

# Compiles and Generates Dependency Info
%.o: %.c
    gcc $(CFLAGS) -c $*.c -o $*.o ${LDLIBS}
    gcc -MM $(CFLAGS) $*.c > $*.d

测试代码编译输出示例

gcc -I/path/to/libservices -L/path/to/libservices services_test.c -o test -lservices

libservices.so: undefined reference to `EVP_CipherInit'
libservices.so: undefined reference to `g_free'
libservices.so: undefined reference to `xmlFreeDoc'
libservices.so: undefined reference to `g_str_equal'
libservices.so: undefined reference to `g_hash_table_lookup'
libservices.so: undefined reference to `__gmpz_get_str'
libservices.so: undefined reference to `EVP_CIPHER_CTX_block_size'
libservices.so: undefined reference to `xmlCheckVersion'
libservices.so: undefined reference to `EVP_EncryptFinal'
libservices.so: undefined reference to `g_hash_table_new'
libservices.so: undefined reference to `EVP_CIPHER_CTX_init'
libservices.so: undefined reference to `xmlNodeGetContent'
libservices.so: undefined reference to `xmlCleanupParser'
libservices.so: undefined reference to `__gmpz_pow_ui'
libservices.so: undefined reference to `EVP_EncryptUpdate'
libservices.so: undefined reference to `__gmpz_clear'
libservices.so: undefined reference to `xmlParseDoc'
libservices.so: undefined reference to `g_hash_table_insert'
libservices.so: undefined reference to `EVP_DecryptInit_ex'
libservices.so: undefined reference to `EVP_EncryptInit_ex'
libservices.so: undefined reference to `g_hash_table_destroy'
libservices.so: undefined reference to `g_list_free'
libservices.so: undefined reference to `EVP_DecryptFinal'
libservices.so: undefined reference to `g_str_hash'
libservices.so: undefined reference to `__gmpz_init_set_str'
libservices.so: undefined reference to `EVP_DecryptUpdate'
libservices.so: undefined reference to `EVP_CipherFinal'
libservices.so: undefined reference to `__gmpz_sizeinbase'
libservices.so: undefined reference to `xmlDocGetRootElement'
libservices.so: undefined reference to `g_hash_table_foreach'
libservices.so: undefined reference to `EVP_CIPHER_CTX_cleanup'
libservices.so: undefined reference to `EVP_CipherUpdate'
collect2: error: ld returned 1 exit status

如果我将它与其他库链接:

gcc -I/path/to/libservices -L/path/to/libservices servicios_test.c -o test -lservices -lssl -lcrypto -lm -lgmp -lz `pkg-config --cflags --libs glib-2.0` `xml2-config --cflags --libs`

然后使用以下命令添加路径:

export LD_LIBRARY_PATH=/path/to/libservices:$LD_LIBRARY_PATH

测试代码运行良好。

【问题讨论】:

  • 编辑您的问题并明确指定您正在为 Java 构建插件、使用什么 Java 运行时以及(如果您知道)如何加载插件可能是个好主意在 Java 代码中。
  • 我会找出所有这些东西并修改问题。我认为客户和我不在同一页面上。谢谢

标签: c gcc compilation shared-libraries self-contained


【解决方案1】:

我认为你或多或少已经完成了。

共享库的全部意义在于包含来自任何其他库依赖项的任何内容。这是运行时链接器的工作,而不是编译时链接器。

由于应用程序显然已经依赖于其他库,因此您的库以及您的库所依赖但应用程序尚未依赖的任何其他库只是要添加到列表中的更多库。

【讨论】:

  • 首先感谢您的回答。现在,根据你所说的,当我被告知生成一个 .so 时,我做了预期的事情,但客户坚持认为它必须是独立的,只需将其应用程序链接到它就可以工作而不需要其他依赖项, 所以我该怎么做? – 将使用该库的客户端代码是 Web Sphere 包含的 Java 应用程序。他们以前使用过这种策略,但主要使用其他人发送给他们的 dll。我不确定我是否在这里遗漏了什么,但根据他们的说法,它也可以与 .so 一起使用。
  • 好吧,如果“自包含”是指它对其他共享对象没有间接依赖关系,那将是愚蠢的,尤其是在最近的 Solaris 系统上。我想我完全理解他们对自包含二进制可执行文件的渴望,但是当他们选择 Solaris 时,他们失去了这个目标,如果您正在构建的是应用程序启动后加载的共享对象,则更是如此 - 即一个插件。
  • 嗯... JNI 的插件?
【解决方案2】:

理论上这是可能的,但我想不出走这条路的合理理由。也很难做到。就代码而言,您应该这样做:

LDLIBS = $(shell xml2-config --cflags --libs) $(shell pkg-config --cflags --libs glib-2.0) -Bstatic -lssl -lcrypto -lm -lgmp -lz

通过添加 -Bstatic,您可以指示链接器使用以下库的 static 版本。但是有一个问题:库的静态版本必须存在于您编译 .so 的系统上。其中一些可能默认存在,但您必须做额外的工作:

  • libmlibgmplibz - 操作系统中很可能有包含这些静态版本的软件包,您必须安装它们(通常包名称是 lib${LIBNAME}-staticlib${LIBNAME}-devel)
  • 对于 libcryptolibssl,您必须将 OpenSSL 重新编译为静态库。

【讨论】:

  • 感谢您的回答。我不知道在这里做什么,因为我有点明白客户的意思,但同时也不完全是您期望使用共享库的方式。也正如我在另一条评论中所说,将使用该库的客户端代码是 Web Sphere 包含的 Java 应用程序。他们以前使用过这种策略,但主要是使用其他人发送给他们的 dll。我不确定我是否在这里遗漏了什么,但根据他们的说法,它也可以与 .so 一起使用。
  • BWT,如果 -Bstatic 令人困惑或导致问题,因为它在命令行上的错误位置结束,我很确定(但目前无法访问现代 Solaris测试)Solaris 链接器仍将通过从它们加载任何必要的对象来正确处理命令行上的lib*.a 文件,并且仅当库由-lname 指定时才需要-Bstatic
  • 是的,我注意到LDLIBS 宏很复杂(它应该包含简单的标志链接器标志)。 -Bstatic 在常规 SunOS 上不起作用,因为默认情况下静态库不存在。动态的是,如果你安装静态的,你将拥有两者。默认情况下,现代操作系统更喜欢动态版本而不是静态版本,这就是需要它的原因。但无论如何,我不喜欢这种方法,他们应该在生产服务器上安装所需的库(大多数是默认的)。此外,我不确定以前的 dll 是否是自包含的,或者它们的依赖项只是碰巧存在。
猜你喜欢
  • 2016-02-22
  • 1970-01-01
  • 1970-01-01
  • 2020-11-18
  • 1970-01-01
  • 1970-01-01
  • 2016-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多