假设有两个模块A 和B, A有两个文件 libClass.h, libClass.cpp; B有两个文件, libClient.h, libClient.cpp.
代码如下:
libClass.h:
#ifndef __LIBCLASS_H__
#define __LIBCLASS_H__
class MyTest
{
public:
static bool Foo(int a, char c);
};
#endif //ifndef __LIBCLASS_H__
libClass.cpp:
#include "libClass.h"
bool MyTest::Foo(int a, char c)
{
return false;
}
libClient.h:
#ifndef __LIBCLIENT_H__
#define __LIBCLIENT_H__
class ClientClass
{
public:
void TestFoo(void);
};
#endif//__LIBCLIENT_H__
libClient.cpp:
#include "libClient.h"
#include "libClass.h"
void ClientClass::TestFoo(void)
{
int a = 10;
char c = 's';
MyTest::Foo(a, c);
}
最后是一个测试程序 test.cpp:
#include "libClient.h"
int main(void)
{
ClientClass client;
client.TestFoo();
return 0;
}
在命令行分别把两个类文件编到两个静态库里面:
g++ -c libClass.cpp
ar rv libClass.a libClass.o
g++ -c libClient.cpp
ar rv libClient.a libClient.o
最后编译测试程序:
g++ test.cpp libClient.a libClass.a
没有问题。
现在,改一下 第一个类的接口:
libClass.h:
#ifndef __LIBCLASS_H__
#define __LIBCLASS_H__
class MyTest
{
public:
static bool Foo(int a, char c, long *p = 0);
};
#endif //ifndef __LIBCLASS_H__
libClass.cpp:
#include "libClass.h"
bool MyTest::Foo(int a, char c, long *p)
{
return false;
}
重新编译一下:
g++ -c libClass.cpp
ar rv libClass.a libClass.o
然后,编译测试程序:
g++ test.cpp libClient.a libClass.a
libClient.a(libClient.o): In function `ClientClass::TestFoo()':
libClient.cpp:(.text+0x20): undefined reference to `MyTest::Foo(int, char)'
collect2: ld returned 1 exit status
说起来应该不发生错误才对,因为增加的只是一个函数的默认参数,client 代码不用修改。
但是从错误信息来看,另一类生成的目标代码已经记忆了原来的类的接口信息,所以如果不更新另一个类的目标代码,链接惠出错。
我们检查一下 libClient.o 的符号表:
charles@China:/WinD/Code/myTest$ nm -C libClient.o
00000000 T ClientClass::TestFoo()
U MyTest::Foo(int, char)
U __gxx_personality_v0
果然,client目标代码里面的函数 Foo()符号还是修改之前的那个。现在这个函数接口参数已经被修改了,所以会发生错误。
现在重新编译 libClient.cpp:
rm libClient.o
cc -c libClient.cpp
ar rv libClient.a libClient.o
然后, 再检查一下符号表:
charles@China:/WinD/Code/myTest$ nm -C libClient.o
00000000 T ClientClass::TestFoo()
U MyTest::Foo(int, char, long*)
U __gxx_personality_v0
现在, client的符号表更新了。然后再链接,就没有问题。
由此得出一个结论,使用静态链接的时候,如过一个模块的接口(或者全局变量)有变更,除了该模块要重新编译外,其他依赖于这个模块的代码也要重新编译。