扩展大型C编程项目 - 对各种功能的未定义参考

时间:2015-10-30 14:45:36

标签: c eclipse gcc makefile configure

我希望扩展一个大型C编程项目(http://icecast.org/download/)以及一些额外的功能。虽然我有一般的编程经验,但这是我第一次在C中做任何事情并且有一些挣扎。

我决定在使用自己的模块扩展Icecast项目时,我会首先在我自己的机器上测试模块(使用Eclipse的Centos 6),一旦工作 - 我的意图是将更改集成到主要的Icecast项目中。 / p>

我的第一个集成是一个日志记录机制,它将简单的消息保存到本地MySQL数据库,我已经成功地在我的机器上运行了这个。我将代码复制到Icecast项目的模块中,确保所有相关的包含都被声明。当尝试使用./configure使用附加功能编译Icecast时,make - 我收到以下错误:

client.o: In function `logSingleMessage':
/home/hearme/radio/src/client.c:283: undefined reference to `mysql_init'
/home/hearme/radio/src/client.c:297: undefined reference to `mysql_real_connect'
/home/hearme/radio/src/client.c:305: undefined reference to `mysql_query'
/home/hearme/radio/src/client.c:307: undefined reference to `mysql_error'
/home/hearme/radio/src/client.c:308: undefined reference to `mysql_close'
/home/hearme/radio/src/client.c:293: undefined reference to `mysql_error'
/home/hearme/radio/src/client.c:312: undefined reference to `mysql_close'

有人可以解释为什么会这样吗?

谢谢

2 个答案:

答案 0 :(得分:2)

您报告的消息是链接器错误。它们表明您的程序试图调用指定的函数,但没有实现它们的链接。应该将相应的库添加到链接中,可能是-lmysqlclient,但可能是-lmysqlclient_r。如何实现这一点很大程度上取决于构建系统的细节。

答案 1 :(得分:0)

您正在分发使用GNU Autotools构建的项目 不幸的是,你选择了一个自动化项目,为你在C的第一次冒险。 你不需要学习autools来学习C,而且真正了解构建C程序或者是非常重要的 在处理自动化项目之前,使用GNU make创建库。自动工具 本质上是一个makefile生成系统,它使其输出适应它对系统的调查结果 根据您提供的配置方向工作。

您需要了解使用已编译的autotools来处理典型的Unix / Linux OSS项目 语言。这不是一项简单的学习,但如果您在icecast autoreconf上取得很大进展,那么 要学习至少基本的知识。 autoconf automake是主要工具。谷歌搜索 " {autoconf | automake} {tutorial | hello world}"将是更有帮助,但不是 比你想象的更有帮助。存在一个名为autoconf的附加驱动程序脚本 可以按正确的顺序自动运行automakeicecast和不太知名的自动工具, 但它不会让你不必阅读和写入这些工具的输入文件。

我可能会让您解决您的直接问题,这会给您留下可能或可能不会的印象 说服你推迟icecast的分支,直到你从较小的挑战中毕业。我的建议 将是推迟。

令人遗憾的是autoconf(我已经抓住它)的自动调整既复杂又过时。每当 您在其上运行automakelibmysqlclient的当前版本,它们会发出一些过时的警告 在项目中进行自动调整。我们先解决这些问题。

您正在为icecast添加新功能,这会在libmysqlclient上引入构建时依赖性。 这意味着构建需要找到mysql用于链接和mysql/mysql.h标题 你编译。出于目前的目的,我假设./configure是您唯一要提及的。

您需要让autotools在生成新的autoconf脚本时处理这些功能要求 对于项目,它将反过来生成所有的makefile。要做到这一点,你将不得不修改 automakeautoreconf的相关输入文件,然后在项目中重新运行这些工具(我们将使用./configure来执行此操作)。之后, 你有一个yum whatprovides autoconf automake libtool 脚本,直到你下次需要干扰构造时才会有用 该项目。

首先,如果您尚未安装autotools,请在您的开发系统上安装。我不知道Centos但是 片刻的谷歌搜索表明:

yum groupinstall 'Development Tools'

之类的应该告诉你所需的包裹,并且:

icecast

以root为基础将一次性完成所有这些工作。

您必须应用我要在原始TODO 2.4.2源代码树中描述的更改。 tarball。它们不依赖于您的任何新源代码,以及何时出现新的源代码 并自动化到包中(对于你来说是mysql),它们将满足其autoreconf依赖项。如果您将它们应用于您所在的源树上 已经对自动变速器进行了修改,当然所有的投注都已关闭。

<强>预赛

在原始源代码树中,运行aclocal: warning: autoconf input should be named 'configure.ac', not 'configure.in',看看它在获得包装时有什么说法。

我收到一堆警告: -

1)configure.in:106: warning: AC_LANG_CONFTEST: no AC_LANG_SOURCE call detected in body ../../lib/autoconf/lang.m4:193: AC_LANG_CONFTEST is expanded from... ../../lib/autoconf/general.m4:2729: _AC_RUN_IFELSE is expanded from... ../../lib/m4sugar/m4sh.m4:639: AS_IF is expanded from... ../../lib/autoconf/general.m4:2748: AC_RUN_IFELSE is expanded from... m4/xiph_curl.m4:6: XIPH_PATH_CURL is expanded from... configure.in:106: the top level

......反复,并且:

2)

src/avl/Makefile.am:13: warning: 'INCLUDES' is the old name for 'AM_CPPFLAGS' (or '*_CPPFLAGS')

......反复,并且:

3)src/httpp/Makefile.am:12: warning: 'INCLUDES' is the old name for 'AM_CPPFLAGS' (or '*_CPPFLAGS')

4)src/net/Makefile.am:13: warning: 'INCLUDES' is the old name for 'AM_CPPFLAGS' (or '*_CPPFLAGS')

5)src/thread/Makefile.am:13: warning: 'INCLUDES' is the old name for 'AM_CPPFLAGS' (or '*_CPPFLAGS')

6)configure.in

在进一步操作之前,您最好先解决这些问题,否则它们会掩盖您之后引发的诊断问题。 自己的错误。首先是明显的:

1)将configure.ac重命名为src/avl/Makefile.am

3)修改INCLUDES并将AM_CPPFLAGS替换为src/httpp/Makefile.am

4)修改INCLUDES =并将AM_CPPFLAGS +=替换为m4/xiph_curl.m4注意差异

5)按照3。

6)按照3。

警告2)是由 AC_RUN_IFELSE(AC_LANG_SOURCE([ #include <curl/curl.h> int main() { return 0; } ]),,[curl_ok="no"],[curl_ok="yes"]) 中缺少一对方括号引起的。编辑它 文件和替换:

    AC_RUN_IFELSE([AC_LANG_SOURCE([
#include <curl/curl.h>
int main()
{
    return 0;
}
]),,[curl_ok="no"],[curl_ok="yes"]])

使用:

autoreconf

现在再次运行./configure,它应该没有任何抱怨。然后运行make, 哪个应该成功完成,最后运行libmysqlclient,这也应该是好的。

修复

现在,您已准备好对libmysqlclient依赖项进行自己的更改。

出于演示目的,我假设你要添加的功能 取决于icecast被称为&#34; Yoyo&#34;,并且你想要它 对于试图在他们身上构建./configure的人来说,这是一个额外的而不是必需的 你的包中有自己的系统。因此,您不希望无法检测到该库或头文件 在configure.ac时间致命。我假设您只想让构建禁用Yoyo 在这种情况下的支持。

修改configure.in(以前为AC_CHECK_HEADERS([pwd.h unistd.h grp.h sys/types.h],,,AC_INCLUDES_DEFAULT) )。找到这一行:

AC_CHECK_HEADERS(
    [mysql/mysql.h],[AM_CONDITIONAL([HAVE_MYSQL_MYSQL_H],[true])],
    [AM_CONDITIONAL([HAVE_MYSQL_MYSQL_H],[false])]
    [AC_MSG_WARN([Header mysql/mysql.h not found. Yoyo support disabled])])

并在其后插入:

autoconf

在这里,您要插入一个./configure宏来指示生成的mysql/mysql.h脚本 检查是否有必要的标题configure.ac,记录该检查的结果并导致脚本 如果未找到标头,则发出警告。见AC_CHECK_HEADERS

接下来,仍在XIPH_PATH_SPEEX( [ XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$SPEEX_CFLAGS]) XIPH_VAR_PREPEND([XIPH_LIBS],[$SPEEX_LIBS]) XIPH_VAR_APPEND([XIPH_LDFLAGS],[$SPEEX_LDFLAGS]) ICECAST_OPTIONAL="$ICECAST_OPTIONAL format_speex.o" ], [ AC_MSG_WARN([Speex support disabled!]) ]) 中,找到节:

AC_CHECK_LIB(
    [mysqlclient],[mysql_init],
    [AC_DEFINE([HAVE_LIBMYSQLCLIENT],[1],[Define if you have libmysqlclient])]
        [AM_CONDITIONAL([HAVE_LIBMYSQLCLIENT],[true])] [MYSQL_LIBS="-lmysqlclient"],
    [AM_CONDITIONAL([HAVE_LIBMYSQLCLIENT],[false])] 
        [AC_MSG_WARN([libmysqlclient not found. Yoyo support is disabled])])

之后插入:

autoconf

在此,您需要插入./configure宏,指示mysql_init检查是否可以 链接一个测试程序,该程序调用外部函数libmysqlclient对库./configure。那&#39; S 对正确库的可用性进行身份验证检查。宏将再次MYSQL_LIBS 记录结果并在检查失败时发出警告。并且,如果检查成功,则变量 我会定义-lmysqlclient = AC_SUBST(KATE_LIBS) 。见AC_CHECK_LIB

再向下,找到行:

AC_SUBST(MYSQL_LIBS)

之后插入:

@MYSQL_LIBS@

添加此行的一个影响是,如果您使用表达式MYSQL_LIBS 在automake的输入文件中的任何地方,然后在从它们生成的makefile中 表达式将替换为autoconf时分配给configure.ac的值(如果有) -lmysqlclient个进程libmysqlclient。如果库可用,该值将为icecast 否则没什么。见AC_SUBST

最后阶段是利用最后一个事实。我会假设Yoyo需要Makefile.am 只是与./configure可执行文件链接。如果它应该与任何其他目标相关联 对于冰球构造或者尚未存在的Yoyo目标,你可以用你现在看到的那种方式实现这一目标。

在构建某个目标的每个子目录中,您将找到src/Makefile.am。该文件是架构 最终控制目标是如何在包裹着陆的任何系统上构建的,由指导 由icecast_LDADD = $(icecast_DEPENDENCIES) @XIPH_LIBS@ @KATE_LIBS@ 提出的当地调查结果和偏好。你可以研究这个过程。

编辑文件_LDADD。这是控制icecast可执行文件的模式的模式。 找到这一行:

icecast

此行示意性地指定icecast_LDADD = $(icecast_DEPENDENCIES) @XIPH_LIBS@ @KATE_LIBS@ @MYSQL_LIBS@ 程序的附加链接器标志autoreconf)。更改 这一行:

./configure

这就是为了你眼前的问题。

查看

现在再次运行icecast并且(如果没有出现错误)它将生成mysqlclient 能够使make clean版本自动适应libmysqlclient dev支持的可用性的脚本, 或者因此缺乏。

观察效果。运行./configure以重新开始。暂时卸载 configure: WARNING: Header mysql/mysql.h not found. Yoyo support disabled configure: WARNING: libmysqlclient not found. Yoyo support is disabled 及其标题(或暂时隐藏它们,例如通过重命名)。 然后运行make。它会成功,但输出将包括 警告:

libmysqlclient

然后运行make clean ./configure 。它成功,构建与上次相同。

现在重新安装./configure及其标题。运行:

Yoyo support disabled

src/Makefile成功,但现在src/Makefile.in警告消失了。

打开文件src/Makefile.am(不是icecastMYSQL_LIBS)。这个 是MYSQL_LIBS = -lmysqlclient 可执行文件的生成的makefile。搜索icecast_LDADD 你找到了设置:

-lmysqlclient

然后搜索make | grep '\-lmysqlclient',您会发现其设置包含libmysqlclient

运行icecast。构建成功,您看到AC_CHECK...configure.ac可执行文件中链接。你还没有做任何事情,但是 当你需要它时它会存在。

我说过你configure中插入的mysql宏会 使AM_CONDITIONAL脚本记录结果。他们以两种方式记录这些结果 您可以使用有条件地集成Yoyo功能,取决于 AC_CHECK_HEADERS( [mysql/mysql.h], # <-- Header to look for [AM_CONDITIONAL([HAVE_MYSQL_MYSQL_H],[true])], #<-- Do this if found # Else do this all... [AM_CONDITIONAL([HAVE_MYSQL_MYSQL_H],[false])] [AC_MSG_WARN([Header mysql/mysql.h not found. Yoyo support disabled])]) 支持的可用性。

其中一种方式是我们使用的AM_CONDITIONAL提供的,例如

automake

Makefile.am的效果是让你写src/Makefile.am个条件 在任何定义目标构建的if HAVE_LIBMYSQLCLIENT # ... Do this if libmysqlclient is available endif 中,例如你 编辑else...endif并插入以下内容:

./configure

当然还有make变体。 ./configure生成时 从这个最终的makefile,它将包括在范围内的东西 真实的条件,省略其余的。

这种形式的检查结果记录可让您将结果传达给config.h。 另一种方法是让您将结果直接传递给编译器

在您运行/* config.h. Generated from config.h.in by configure. */ /* config.h.in. Generated from configure.ac by autoheader. */ 之后,您会发现有一个顶级的头文件 包树名为mysqlclient。打开它,在顶部会告诉你 它是如何存在的:

HAVE_MYSQL_MYSQL_H

上次生成此文件时,您已安装/* Define to 1 if you have the <mysql/mysql.h> header file. */ #define HAVE_MYSQL_MYSQL_H 1 dev支持。 在文件中搜索HAVE_LIBMYSQLCLIENT,您会发现:

/* Define if you have libmysqlclient */
#define HAVE_LIBMYSQLCLIENT 1

搜索config.h,然后找到

./configure

您可以依赖它,这些宏将在-DHAVE_CONFIG_H中定义 当且仅当它们所代表的检查成功时才为非零值 {{1次。您也可以依赖命令行预处理器 选项make将自动传递给所有编译器命令 在-I以及config.h(包含搜索路径)选项中将启用 编译器来定位#ifdef HAVE_CONFIG_H #include <config.h> #endif 。因此,您可以在任何C源文件中使用 写:

./configure

然后在源文件的主体中,您可以访问并使用预处理器 表示#if HAVE_MYSQL_MYSQL_H #include <mysql/mysql.h> #endif - 时间检查结果的宏,例如

icecast

<强>最后

在这里, not 勾勒出正确的是将Yoyo整合到icecast-with-yoyo中。 我已经草拟了一种方法,您可以制作icecast Yoyo的依赖性得到满足,否则产生./configure经典, 所以你仍然没有 的自动工具。但它会被评为粗鲁和业余自动调整。

提供Yoyo作为可选功能的正确方法是装备 带有命令行参数--enable-yoyo的{​​{1}}脚本 并在./configure --help中记录它,以便安装程序 打包并选择是否构建Yoyo支持。然后,如果我没有./configure --enable-yoyo,不会建立yoyo支持。但如果我确实指明了 如果不满足Yoyo的依赖关系,那么选项./configure应该失败。 您使用AC_MESSAGE_ERROR代替AC_MESSAGE_WARN, 而你的configure.ac会变得更精细。如果您想要调查如何实施此类./configure 您可以从AC_ARG_ENABLE

开始参数