在C语言中从归档文件(.a)创建共享库

3
我被分配了一个任务,需要从目标文件创建归档文件.a,然后从这个归档文件创建共享库文件。我已经进行了以下实验:
foo.h
#ifndef _foo_h__
#define _foo_h__
extern void foo(void);
extern void bar(void); 
#endif //_foo_h__


foo.c

#include<stdio.h>

void foo(void)
{
    puts("Hello, I'm a shared library");
}


bar.c

#include<stdio.h>

void bar(void)
{
    puts("This is bar function call.");
}


main.c

#include <stdio.h>
#include"foo.h"

int main(void)
{
    puts("This is a shared library test...");
    foo();
    bar();
    return 0;
}


Makefile

CFLAGS = -Wall -Werror
LDFLAGS = -L/home/betatest/Public/implicit-rule-archive -Wl,-rpath,'$$ORIGIN'

all : run

run : main.o libfoo.so
    $(CC) $(LDFLAGS) -o $@ $^

libfoo.so : CFLAGS += -fPIC # Build objects for .so with -fPIC.
libfoo.so : libfoo.a
    $(CC) -shared -o $@ $^

libfoo.a : foo.o bar.o
    ar cvq libfoo.a foo.o bar.o
#   ar cr libfoo.a foo.o bar.o

# Compile any .o from .c. Also make dependencies automatically.
%.o : %.c
    $(CC) -c $(CFLAGS) -o $@ $<

#Include dependencies on subsequent builds.

.PHONY : all clean

clean :
    -rm -f *.o *.d run libfoo.*

这个简单的测试程序看起来运行良好,但使用make编译时会产生错误,错误内容如下:

cc -c -Wall -Werror -o main.o main.c
cc -c -Wall -Werror -fPIC  -o foo.o foo.c
cc -c -Wall -Werror -fPIC  -o bar.o bar.c
ar cvq libfoo.a foo.o bar.o
a - foo.o
a - bar.o
cc -shared -o libfoo.so libfoo.a
cc -L/home/betatest/Public/implicit-rule-archive -Wl,-rpath,'$ORIGIN' -o run main.o libfoo.so
main.o: In function `main':
main.c:(.text+0xf): undefined reference to `foo'
main.c:(.text+0x14): undefined reference to `bar'
collect2: ld returned 1 exit status
Makefile-test:7: recipe for target 'run' failed
make: *** [run] Error 1

有人能指出我哪里错了吗?非常感谢。

1
你没有链接共享库:请尝试使用-lfoo而不是libfoo.so - Michele d'Amico
cc 在 $ORIGIN 周围得到了单引号。尝试省略它们。 - William Pursell
2个回答

8
如果您希望从静态库构建一个共享库,那么您需要告诉链接器使用静态库(.a)中包含的所有函数/符号。否则,在共享库(.so)中将不会包含任何内容。
在链接时,您需要使用--whole-archive/--no-whole-archive配对选项。
CFLAGS = -Wall -Werror
LDFLAGS = -L/home/betatest/Public/implicit-rule-archive -Wl,-rpath,'$$ORIGIN'

all : run

run : main.o libfoo.so
    $(CC) $(LDFLAGS) -o $@ $^

libfoo.so : CFLAGS += -fPIC # Build objects for .so with -fPIC.
libfoo.so : libfoo.a
    $(CC) -shared -o $@ -Wl,--whole-archive $^  -Wl,--no-whole-archive

libfoo.a : foo.o bar.o
     ar cvq libfoo.a foo.o bar.o

# Compile any .o from .c. Also make dependencies automatically.
%.o : %.c
    $(CC) -c $(CFLAGS) -o $@ $<

#Include dependencies on subsequent builds.

.PHONY : all clean

clean :
    -rm -f *.o *.d run libfoo.*

您可以使用 nm 命令来检查导出的函数:
$ nm -D libfoo.so | grep  ' T '
0000000000000702 T bar
0000000000000714 T _fini
00000000000006f0 T foo
0000000000000590 T _init

当没有使用--whole-archive/--no-whole-archive时,您会得到:

$ nm -D libfoo.so | grep  ' T '
0000000000000714 T _fini
0000000000000590 T _init

感谢@ctheo先生!!!!编译顺利进行,编译输出为: cc -c -Wall -Werror -o main.o main.c ; cc -c -Wall -Werror -fPIC -o foo.o foo.c; cc -c -Wall -Werror -fPIC -o bar.o bar.c; ar cvq libfoo.a foo.o bar.o; a - foo.o; a - bar.o; cc -shared -o libfoo.so -Wl,--whole-archive libfoo.a -Wl,--no-whole-archive; cc -L/home/betatest/Public/implicit-rule-archive -Wl,-rpath,'$ORIGIN' -o run main.o libfoo.so; 我想问一下main.o是如何生成的,它是隐式规则还是下面定义的模式?谢谢! - Abhijatya Singh
主文件 main.o 是通过命令 cc -c -Wall -Werror -o main.o main.c 构建的。它使用了 CFLAGS,但没有加上 -fPIC,因为 libfoo.so 不依赖于它。 - ztik
1
这意味着它看到一个依赖关系 main.o 并调用定义的模式规则 %.o : %.c。谢谢。 - Abhijatya Singh

1
你的错误在于问题本身:不要从归档文件中创建共享库,而是从目标文件中创建,即将Makefile更改为以下内容。
libfoo.so : foo.o bar.o
    $(CC) -shared -o $@ foo.o bar.o

你也可以使用%.o代表所有对象。
此外,你需要在全局范围内使用CFLAGS = -fPIC,以影响编译命令,而不仅仅是链接步骤,即你的.o目标文件应该是位置无关的。
此外,在这里extern是不必要的,所有C函数都隐式地是extern。
extern void foo(void);

我也不建议使用rpath,最好

export LD_LIBRARY_PATH=.

从当前目录加载.so文件(或将路径导出到.so文件所在的目录)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接