【问题标题】:How to link app with static library + why this is not working如何将应用程序与静态库链接 + 为什么这不起作用
【发布时间】:2010-03-29 15:33:04
【问题描述】:

我有问题。我写了示例代码,我想构建它没有错误:

main.cpp(.text+0x5): undefined reference to `test()'

图书馆


test1.c

#include <stdlib.h>
void test()
{
 puts("Działa");
}

test1.h

#ifndef TEST1_H
#define TEST1_H

extern void test();

#endif

制作文件

all:
 gcc -c ./src/test1.c -o ./lib/test1.o
 ar rcs ./lib/libtest1.a ./lib/test1.o

程序


main.cpp

#include <test1.h>

int main()
{
 test();
 return 0;
}

制作文件

all:
 g++ -static -I../test1/include -L../test1/lib ./src/main.cpp -o ./build/MyApp -ltest1

我做错了什么?

【问题讨论】:

    标签: c++ c linux gcc g++


    【解决方案1】:

    您正在编译一个 C 代码函数,但您希望链接一个 C++ 函数。

    由于“类型安全链接”,您提供的函数不是 C++ 代码调用的函数。

    在 test1.h 中使用:

    #ifdef __cplusplus
    extern "C" {
    #endif
    
    extern void test1(void);
    
    #ifdef __cplusplus
    }
    #endif
    

    或者:

    • 使用 C++ 编译器编译函数。

    C++ 编译器将修改符号名称以提供类型安全的链接(您应该能够通过首选搜索引擎搜索的术语)。

    “编译器”(实际上是链接器)正在寻找一个具有 C++ 重整名称的函数,该函数代表带有签名“void test1(void);”的 C++ 函数。

    例如(但请记住——不同的编译器会故意以不同的方式处理),MacOS X 10.6.2 上的 G++ 4.2.1 会为函数生成符号“__Z5test1v”; GCC 生成一个符号“_test1”。显然,当链接器正在寻找“__Z5test1v”时,不会使用符号“_test1”——它的拼写不同。这是一件好事。

    您可以在主程序的目标文件上使用“nm -g”来查看它正在寻找什么,并在库中的目标文件上使用它来查看它提供的内容。而且,由于拼写不同,这就是加载程序不选择库函数的原因——它正在寻找具有不同名称的东西。

    【讨论】:

    • @Jonathan:这是一个有效的观点,但它不能解释编译器错误。
    • @quamrana:是的。 “编译器”——实际上是链接器——正在寻找一个具有 C++ 重整名称的函数,该函数代表带有签名“void test1(void);”的 C++ 函数。例如,MacOS X 10.6.2 上的 G++ 4.2.1 为函数生成符号 '__Z5test1v'; GCC 生成一个符号“_test1”。显然,当链接器查找“__Z5test1v”时,不会使用符号“_test1”——它的拼写不同。
    • 哦,我明白了——我一直忘记 gcc 可以链接和编译。 +1 以获得更好的答案。
    • 这就是 gcc 可以为您提供链接器错误的行号吗?如果很多行都引用了一个未定义的符号会发生什么?
    • @quamrana:在示例中,编译器没有给你行号;它为您提供了参考出现的文本(代码)的偏移量。如果你有调试符号(用'-g'编译),那么目标文件中有关于行号等的信息,你可能会得到更好的信息。
    【解决方案2】:

    您正在从 C++ 函数调用 C 函数。两者的命名是不同的(C++ 修改名称以包含参数信息)。

    把头文件改成这样:

    #ifdef __cplusplus
    extern "C" {
    #endif
    
    extern void test();
    
    #ifdef __cplusplus
    }
    #endif
    

    这将告诉编译器该函数遵循 C 命名/调用约定。

    【讨论】:

    • 大括号后的分号是必需的、可选的还是“必须不存在”?我查看了我的一些代码并且没有分号,所以我在答案中就是这样写的。你有它......你知道谁更接近正确吗?
    • @Jonathan 它不应该存在 - 使用 -Wall 和 -pedantic 编译的 g++ 会对此发出警告。它的目的是终止可以在类、结构等之后出现的名称列表,但在 extern 块之后不能有这样的列表。
    • 同意。分号不应该在那里。只是类声明中的一种习惯......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多