【问题标题】:C++ program calling C Function Getting Undefined References During g++ linkingC++ 程序调用 C 函数在 g++ 链接期间获取未定义的引用
【发布时间】:2018-03-24 22:08:53
【问题描述】:

我有一个调用 C 函数的简单 C++ 程序。当我链接 2 个目标文件以创建 C++ 可执行文件时,我收到许多“未定义引用”错误和单个“对 svrport 的多个引用”错误。我有以下文件 chorusmain.cpp、chorusclient.c 和 chorusclient.h。 chorusmain.cpp 调用 chorusclient.c 中的函数。 chorusclient.c 非常大,我是在 2 年前写的。我现在需要在 C++ 应用程序中使用这些函数,并且不想用 C++ 重新编写并重新调试代码。我将 chorusclient.c 重构为一组可调用函数。为简单起见,我将代码简化为仅重要的组件。

chorusclient.c

#include <...>
#include "chorusclient.h"

int my_C_Function()
{
  ...
}

chorusclient.h

#ifdef __cplusplus
extern "C" {
#endif

int my_C_Function();

#ifdef __cplusplus
}
#endif

chorusmain.cpp

#include <...>
#include "chorusclient.h"

int main(int argc, char *arvg[])
{
  ...
  my_C_Function();
  ...
}

这里是 gcc/g++ 构建和链接命令,

gcc -c -o chorusclient.o chorusclient.c -I/usr/include/json-c - 
    I/usr/include/openssl -I/usr/include -I. -I. -lssl -lcrypto -ljson-c

g++ -c -o chorusmain.o chorusmain.cpp -I/usr/share/qt4/mkspecs/linux-g++ -I. - 
    I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 - 
    I/usr/include -I. -I. -lQtGui -lQtCore -lpthread

g++ -o ChorusMain chorusclient.o chorusmain.o

前 2 个 gcc/g++ 构建没有错误。我在 g++ 链接期间收到以下未定义的引用错误,

debian@beaglebone:~/Projects/CloudClient$ ls
chorusclient.c  chorusclient.h  chorusclient.o  chorusmain.cpp  chorusmain.o
debian@beaglebone:~/Projects/CloudClient$ g++ -o ChorusMain chorusmain.o chorusclient.o
chorusclient.o:(.data+0x0): multiple definition of `svrport'
chorusmain.o:(.data+0x0): first defined here
chorusclient.o: In function `chorusServices':
chorusclient.c:(.text+0x408): undefined reference to `OPENSSL_init_crypto'
chorusclient.c:(.text+0x416): undefined reference to `OPENSSL_init_crypto'
chorusclient.c:(.text+0x41c): undefined reference to `OPENSSL_config'
chorusclient.o: In function `httpSend':
chorusclient.c:(.text+0x1c2c): undefined reference to `OPENSSL_init_ssl'
chorusclient.c:(.text+0x1c3a): undefined reference to `OPENSSL_init_ssl'
chorusclient.c:(.text+0x1c4c): undefined reference to `OPENSSL_init_ssl'
chorusclient.c:(.text+0x1c50): undefined reference to `TLSv1_2_client_method'
chorusclient.c:(.text+0x1c58): undefined reference to `SSL_CTX_new'
chorusclient.c:(.text+0x1c62): undefined reference to `SSL_CTX_set_options'
chorusclient.c:(.text+0x1c7e): undefined reference to `ERR_print_errors_fp'
chorusclient.c:(.text+0x1ca0): undefined reference to `SSL_new'
chorusclient.c:(.text+0x1caa): undefined reference to `SSL_set_fd'
chorusclient.c:(.text+0x1cb0): undefined reference to `SSL_connect'
chorusclient.c:(.text+0x1ce4): undefined reference to `SSL_get_peer_certificate'
chorusclient.c:(.text+0x1cec): undefined reference to `X509_get_subject_name'
chorusclient.c:(.text+0x1cfa): undefined reference to `X509_NAME_oneline'
chorusclient.c:(.text+0x1d1a): undefined reference to `X509_get_issuer_name'
chorusclient.c:(.text+0x1d28): undefined reference to `X509_NAME_oneline'
chorusclient.c:(.text+0x1d3e): undefined reference to `X509_free'
chorusclient.c:(.text+0x1d4a): undefined reference to `SSL_get_current_cipher'
chorusclient.c:(.text+0x1d52): undefined reference to `SSL_CIPHER_get_name'
chorusclient.c:(.text+0x1d80): undefined reference to `SSL_write'
chorusclient.c:(.text+0x1d90): undefined reference to `SSL_read'
chorusclient.c:(.text+0x1df2): undefined reference to `SSL_read'
chorusclient.c:(.text+0x1e8e): undefined reference to `SSL_free'
chorusclient.c:(.text+0x1e9a): undefined reference to `SSL_CTX_free'
chorusclient.o: In function `jsonBatteryData':
chorusclient.c:(.text+0x21a8): undefined reference to `json_object_new_object'
chorusclient.c:(.text+0x21b2): undefined reference to `json_object_new_string'
chorusclient.c:(.text+0x21be): undefined reference to `json_object_new_string'
chorusclient.c:(.text+0x21ca): undefined reference to `json_object_new_string'
chorusclient.c:(.text+0x21d8): undefined reference to `json_object_new_double'
chorusclient.c:(.text+0x21e6): undefined reference to `json_object_new_double'
chorusclient.c:(.text+0x21f4): undefined reference to `json_object_new_double'
chorusclient.c:(.text+0x2202): undefined reference to `json_object_new_double'
chorusclient.c:(.text+0x2210): undefined reference to `json_object_new_double'
chorusclient.c:(.text+0x2220): undefined reference to `json_object_object_add'
chorusclient.c:(.text+0x222e): undefined reference to `json_object_object_add'
chorusclient.c:(.text+0x223c): undefined reference to `json_object_object_add'
chorusclient.c:(.text+0x224a): undefined reference to `json_object_object_add'
chorusclient.c:(.text+0x2258): undefined reference to `json_object_object_add'
chorusclient.o:chorusclient.c:(.text+0x2266): more undefined references to `json_object_object_add' follow
chorusclient.o: In function `jsonBatteryData':
chorusclient.c:(.text+0x2292): undefined reference to `json_object_to_json_string'
chorusclient.o: In function `blockencrypt':
chorusclient.c:(.text+0x22de): undefined reference to `EVP_CIPHER_CTX_new'
chorusclient.c:(.text+0x22ee): undefined reference to `EVP_aes_256_cbc'
chorusclient.c:(.text+0x22fe): undefined reference to `EVP_EncryptInit_ex'
chorusclient.c:(.text+0x231a): undefined reference to `EVP_EncryptUpdate'
chorusclient.c:(.text+0x233c): undefined reference to `EVP_EncryptFinal_ex'
chorusclient.c:(.text+0x2354): undefined reference to `EVP_CIPHER_CTX_free'
chorusclient.o: In function `decrypt':
chorusclient.c:(.text+0x2370): undefined reference to `EVP_CIPHER_CTX_new'
chorusclient.c:(.text+0x2380): undefined reference to `EVP_aes_256_cbc'
chorusclient.c:(.text+0x2390): undefined reference to `EVP_DecryptInit_ex'
chorusclient.c:(.text+0x23ac): undefined reference to `EVP_DecryptUpdate'
chorusclient.c:(.text+0x23ce): undefined reference to `EVP_DecryptFinal_ex'
chorusclient.c:(.text+0x23e6): undefined reference to `EVP_CIPHER_CTX_free'
chorusclient.o: In function `handleErrors':
chorusclient.c:(.text+0x2404): undefined reference to `ERR_print_errors_fp'
collect2: error: ld returned 1 exit status
debian@beaglebone:~/Projects/CloudClient$

当我创建一个调用 chorusclient.c 的简单 C 程序并构建一个链接时,我没有收到未定义的引用错误,并且程序正常工作。有什么想法吗?

【问题讨论】:

  • 编译成目标文件时列出库;尝试链接可执行文件时没有列出库。这些库在编译目标文件时无关紧要——它们在链接可执行文件时至关重要。
  • 乔纳森,您能否更具体地说明我应该如何格式化 g++ 链接命令?我问的原因是我已经查看了多个带有库的示例。所有示例都在编译期间链接库,然后像我所做的那样在最终链接期间简单地链接目标文件。
  • 你能指定一个你看到的例子的 URL 吗?如果你有一个源文件,那么你可以省略-c 选项(在目标文件阶段停止编译)并添加库,一切都在一个命令中完成。如果您需要多个源文件来制作需要 C 和 C++ 编译的单个程序,则必须有一个单独的链接阶段(使用 C++ 编译器进行链接),并且该链接阶段必须指定库。您可以在一行中列出带有 C++ 源文件和 -I 选项的 C 目标文件和库。

标签: c++ c gcc g++


【解决方案1】:

你说你有:

gcc -c -o chorusclient.o chorusclient.c -I/usr/include/json-c \
    -I/usr/include/openssl -I/usr/include -I. -I. -lssl -lcrypto -ljson-c
g++ -c -o chorusmain.o chorusmain.cpp -I/usr/share/qt4/mkspecs/linux-g++ -I. \
    -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 \
    -I/usr/include -I. -I. -lQtGui -lQtCore -lpthread
g++ -o ChorusMain chorusclient.o chorusmain.o

您在编译创建目标文件时列出库;尝试链接可执行文件时没有列出库。这些库在创建目标文件时无关紧要——它们在链接可执行文件时至关重要。

因此,您需要更多类似的东西:

gcc -Wall -Werror -c -o chorusclient.o chorusclient.c -I/usr/include/json-c \
    -I/usr/include/openssl -I/usr/include -I. 
g++ -Wall -Werror -c -o chorusmain.o chorusmain.cpp -I/usr/share/qt4/mkspecs/linux-g++ \
    -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 \
    -I/usr/include -I.
g++ -o ChorusMain chorusclient.o chorusmain.o -lQtGui -lQtCore -lpthread -lssl -lcrypto -ljson-c

我不相信您需要-I/usr/include,而且您通常不需要-I.(除非您坚持使用#include &lt;chorusclient.h&gt; 而不是#include "chorusclient.h"),而且您绝对不需要@ 987654328@重复。

您可能需要对链接中的库列表重新排序 - 最好将 -lpthread 放在末尾附近。

我添加了 -Wall -Werror 选项,因为您不应该尝试运行您的代码,除非它至少在这些选项下干净地编译(我会在我的代码中添加更多 - 这足以说明这一点)。

我有点惊讶您需要-I/usr/include/openssl 行;您是否应该使用 #include &lt;openssl/ssl.h&gt; 等(用于 OpenSSL 标头)以便不需要 -I/usr/include/openssl 命令行选项?类似的,也许是 Qt 和 JSON-C 标头?

另一个问题是你有一个对象——可能是一个全局变量——称为svrport,在chorusclient.ochorusmain.o 中都定义了。这意味着通过某种机制,您在两个源文件中定义(而不是声明)相同的对象。这可能是因为它是在头文件中定义而不是声明的(但代码中没有显示)。或者可能是因为您在两个源文件中都定义了它。如果它需要是一个全局变量,它应该在头文件中声明并在其中一个源文件中定义(可能是chorusclient.c,因为chorusclient.h 头文件正在声明它)而不是在另一个文件中定义。

【讨论】:

  • 好的,我尝试了你的建议,得到了以下错误——debian@beaglebone:~/Projects/CloudClient$ g++ -o ChorusMain chorusclient.o chorusmain.o -lQtGui -lQtCore -lpthread -lssl - lcrypto -ljson-c chorusmain.o:(.data+0x0): `svrport' chorusclient.o:(.data+0x0)的多重定义: 首先在这里定义 collect2: error: ld returned 1 exit status debian@beaglebone:~ /Projects/CloudClient$ ls chorusclient.c chorusclient.h chorusclient.o chorusmain.cpp chorusmain.o debian@beaglebone:~/Projects/CloudClient$ 抱歉格式不好。 cmets 中不允许格式化。
  • 是的,cmets 中不允许格式化。这可能是一件麻烦事。您的chorusclient.cchorusmain.cpp 代码中似乎存在一个错误,因此对象(全局变量?)svrport 在两个对象文件中都定义了。由于您没有显示变量,因此无法说出您做错了什么,但我不会惊讶地发现它是在标题中定义的(或者,如果失败,两个文件分别定义它) .但是,它与未定义的引用无关 - 似乎您缺少的符号已经“全部”得到满足。 (我承认我忽略了多重定义错误。)
  • 看来您的建议是正确的。我同意你的说法,我有一个错误。我在编译期间收到了一些警告。一年前我最后一次编译这段代码时没有得到错误。这些似乎来自较新版本的 gcc/g++,它不喜欢我的某些字符串的语法。让我进一步研究一下,看看我发现了什么。
  • 好的,我清理了我的 C 代码警告。我还在 chorusclient.h 中发现了不正确的“const”定义——将“unsigned short svrport = 8443”更改为“const unsigned short svrport = 8443”。这对于“C”是正确的,但在链接到 C++ 目标文件并导致多个定义时不正确。我删除了“-I/usr/include”和“-I”。和额外的“-I”。正如乔纳森推荐的那样。现在一切都可以正确编译和链接。因此,Jonathan 建议将库放在 g++ 链接中并消除额外的库引用是绝对正确的。
  • 我对 svrport 的多次引用是由于 chorusclient.h 中的 svrport 声明不太好。在 C 中可以正常工作,但在 C++ 中不行。有“无符号短 svrport = 8443”。改为“const unsigned short svrport = 8443”,不再获取多个引用见stackoverflow.com/questions/15765529/multiple-definition-of-c
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-03
  • 1970-01-01
  • 2011-04-03
  • 1970-01-01
  • 2014-02-13
相关资源
最近更新 更多