在Linux上使用Makefile编译独立ASIO

时间:2017-02-03 23:25:55

标签: c++ c linux makefile boost-asio

我正在尝试编译一个小型c ++程序,该程序使用libv4l2从摄像头捕获图像,然后通过UDP将其发送到使用asio的单独计算机。

项目的文件结构是:

project/
    dependencies/
        asio/
    cpp/
        cpp_server/
        cpp_client/
            Makefile
            src/
                cpp_client.cpp
                ImageClient.cpp
                ImageClient.h
                ImageProtocol.h

该项目的Makefile是:

CC=g++

CPP_FILES := $(wildcard src/*.cpp)
OBJ_FILES := $(addprefix obj/,$(notdir $(CPP_FILES:.cpp=.o)))
LD_FLAGS := -L../../dependencies/asio/asio
INCLUDES := -I../../dependencies/asio/asio/include

CC_FLAGS := -Wall  $(INCLUDES) -fpermissive -std=c++14 -DASIO_STANDALONE

client.exe : $(OBJ_FILES)
    $(CC) $(LD_FLAGS) -o $@ $^

obj/%.o: src/%.cpp
    $(CC) $(CC_FLAGS) -c -o $@ $<

但是,当我尝试编译时,我的编译器会针对ASIO函数发出数十个undefined reference错误:

cpp_client.cpp:(.text+0x15dc): undefined reference to `asio::error::get_netdb_category()'
cpp_client.cpp:(.text+0x15ec): undefined reference to `asio::error::get_addrinfo_category()'
cpp_client.cpp:(.text+0x15fc): undefined reference to `asio::error::get_misc_category()'
obj/cpp_client.o: In function `asio::error::get_system_category()':
cpp_client.cpp:(.text._ZN4asio5error19get_system_categoryEv[_ZN4asio5error19get_system_categoryEv]+0x8): undefined reference to `asio::system_category()'
obj/cpp_client.o: In function `asio::detail::posix_tss_ptr<asio::detail::call_stack<asio::detail::thread_context, asio::detail::thread_info_base>::context>::posix_tss_ptr()':
cpp_client.cpp:(.text._ZN4asio6detail13posix_tss_ptrINS0_10call_stackINS0_14thread_contextENS0_16thread_info_baseEE7contextEEC2Ev[_ZN4asio6detail13posix_tss_ptrINS0_10call_stackINS0_14thread_contextENS0_16thread_info_baseEE7contextEEC5Ev]+0x20): undefined reference to `asio::detail::posix_tss_ptr_create(unsigned int&)'
obj/cpp_client.o: In function `asio::detail::posix_tss_ptr<asio::detail::call_stack<asio::detail::thread_context, asio::detail::thread_info_base>::context>::~posix_tss_ptr()':
cpp_client.cpp:(.text._ZN4asio6detail13posix_tss_ptrINS0_10call_stackINS0_14thread_contextENS0_16thread_info_baseEE7contextEED2Ev[_ZN4asio6detail13posix_tss_ptrINS0_10call_stackINS0_14thread_contextENS0_16thread_info_baseEE7contextEED5Ev]+0x1c): undefined reference to `pthread_key_delete'
obj/cpp_client.o: In function `asio::detail::posix_global_impl<asio::system_executor::context_impl>::~posix_global_impl()':
cpp_client.cpp:(.text._ZN4asio6detail17posix_global_implINS_15system_executor12context_implEED2Ev[_ZN4asio6detail17posix_global_implINS_15system_executor12context_implEED5Ev]+0x24): undefined reference to `asio::system_executor::context_impl::~context_impl()'
obj/ImageClient.o: In function `ImageClient::ImageClient(FHCamera, unsigned short, std::string const&, unsigned short)':
ImageClient.cpp:(.text+0x898): undefined reference to `asio::io_context::io_context()'

我想问题是我的Makefile仍然没有正确地找到ASIO并尝试独立编译它。也就是说,我不确定还有什么可以尝试的 - 是否有其他人对我需要做些什么来建议让ASIO用Makefile独立编译?

谢谢!

2 个答案:

答案 0 :(得分:2)

独立的Asio库是您程序的依赖。建设时 一个程序,一个也没有建立依赖性(除非特殊情况 情况)。如果这是必要的,那么建立几乎任何程序都会 递归地要求大量的重建依赖。

如果您的程序依赖于未提供打包的库 您的Linux发行版的包管理器然后您必须获取源包 根据其说明,在您的系统上构建和安装该库。

然后根据您的系统满足的(真实)假设构建自己的程序 库依赖。您不会重复构建库依赖项 在你的程序建设中。

独立名字对象可能已经建议您使用此库 意味着要在每个使用它的应用程序中重建。不是。它&#39; S 独立 asio,因为它本身并不依赖于任何人 与boost不同的boost::asio库是派生的。 独立 并不意味着图书馆不依赖于其他图书馆 非增强库。例如。在您的链接错误中有一些错误 将未定义的引用 asio函数报告给pthread_key_delete, 这意味着asio依赖于Posix线程库libpthread, 并且你没有链接它。

独立的Asio库可能在开发包中提供 由Linux发行版的软件包管理器提供。例如,Debian / Ubuntu发行版 在libasio-dev中提供,您只需使用以下命令安装:

sudo apt-get install libasio-dev

调查您的发行版是否同样如此,如果是,请安装库 与您的包管理员。

否则,您必须从源安装库。它是一个 GNU autotools源包, 所以要构建和安装它,你必须先安装:

- GCC C++ toolchain
- GNU make
- GNU autotools (autoconf, automake at least)

然后:

从其下载源代码tarball,例如asio-1.10.8.tar.bz2 Sourceforge page和 提取包目录,例如asio-1.10.8

cd进入包目录并运行:

$ autoreconf -i
$ ./configure

来自./configure的错误将表明依赖性或其他要求 你的系统不满意。修复并重复直至成功。然后运行

$ make

构建包。如果一切顺利,以root身份运行:

$ make install

安装包。

从dev软件包或从中安装Standalone Asio后 来源,删除project/dependencies/asio并构建您的程序 在project/cpp/cpp_client中使用这样的makefile:

<强>生成文件

CXX=g++
SRCS := $(wildcard src/*.cpp)
OBJS := $(addprefix obj/,$(notdir $(SRCS:.cpp=.o)))
CXXFLAGS := -pthread
LDFLAGS := -pthread
#LDFLAGS := -L/path/to/your/libv4l2
#LDLIBS := -libv4l2

.PHONY: all clean 

CXXFLAGS := -Wall -std=c++14 -DASIO_STANDALONE

all: client

client : $(OBJS)
    $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS)

obj/%.o: src/%.cpp | obj
    $(CXX) $(CXXFLAGS) -c -o $@ $<

obj:
    mkdir -p $@

clean:
    rm -f obj/* client

对于排练,我建议首先使用此makefile来构建asio聊天客户端 /asio-package-dir/src/examples/cpp11/chat中提供的内容。只需chat_client.cppchat_message.hpp文件夹中的src

注意注释掉的行:

#LDFLAGS := -L/path/to/your/libv4l2
#LDLIBS := -lv4l2

您表示您的计划需要与图书馆libv4l2相关联 但你自己的makefile没有提到任何这样的链接。如果你确实需要 与它链接然后你必须至少通过链接器告知链接器 取消注释:

LDLIBS := -lv4l2

如果您可以从软件包管理器安装此库的一个软件包,请执行此操作。除此以外 从源代码构建并安装它。 Debian / Ubuntu不提供此类功能 一个图书馆包,虽然他们确实提供了libv4l-0libv4l-devlibv4l2rds0。也许你还不确定你需要什么样的库。

如果您从源安装此库并决定安装它 某个目录不是链接器的默认搜索路径之一 (/usr/lib/usr/local/lib/等...)然后您还需要通知 链接器所在的位置,取消注释:

LDFLAGS := -L/path/to/your/libv4l2

请注意,将libv4l2添加到与-lv4l2的关联中,即可 要求链接器找到libv4l2的任何其他库 反过来取决于。因此,如果您的链接现在因未定义的引用而失败 从libv4l2到其他库libfoo中的符号,您需要 延伸LDLIBS如:

LDLIBS := -lv4l2 -lfoo

并且,如有必要,告诉链接器在哪里找到libfoo

LDFLAGS := -L/path/to/your/libv4l2 -L/path/to/libfoo

依此类推,直到联系成功。

从这个角度来看,你可能想知道为什么asio库没有类似的数字 在联系中。不需要链接器选项-lasio?你自己的makefile建议你 相信链接器需要被告知在哪里寻找这样的库,用 它的设置:

LD_FLAGS := -L../../dependencies/asio/asio
虽然告诉链接器在那里查找图书馆,但你不能告诉它任何链接 图书馆。

不需要-lasio,因为这个库通常是非典型的,但不是 非典型的boostboost - ish库 - 是仅限标头库。 它不提供共享对象文件libasio.so,也不提供任何目标文件存档 libasio.a您必须链接以获取函数的定义。代替, 它们完全由头文件中的内联定义实现。从而, 您需要在程序中调用的任何一个都将直接编译 如果您在源文件中只有#include <asio.hpp>,那就进入它 那些电话。

由于它是一个仅限标题的库, 可以使用它来构建自己的库 程序只需提取源包,跳过常用的autotools ./configure; make;make install过程,并设置预处理器-I选项 在你自己的makefile中正确(在CPPFLAGS - C预处理器标志中) 它可以找到asio标题,例如, /home/me/downloads/asio/asio-1.10.8。但如果你的目标是实现 那个,你犯了一些错误途中;如果包 自动缩减 - 如asio那么 - 如果您尝试使用它,则所有投注都将关闭,除非由autotools提供 安装程序。 在系统中安装库也有 一旦你完成它,你可以忘记设置奇特的好处 每个使用它的项目中的编译器和链接器选项 像/home/me/downloads/asio/asio-1.10.8一样,不需要成为一个 你的主目录的夹具。

你的makefile以及你对它的问题所说的话表明你是 试图通过猜测,试验和错误来使用GCC和GNU Make。这是 a fairly good starter tutorial in the use of those tools。 对于权威文档,这里是the GNU Make manual和 这是the GCC manual

顺便提一下,在Linux中,可执行文件仅通过其文件来区分 属性,而不是像在Windows中那样具有.exe扩展名,所以 您的计划目标可以通常只调用client,而不是client.exe。链接器会在创建它时使其可执行。

答案 1 :(得分:0)

您收到错误,因为在链接步骤中您没有提供生成最终可执行文件所需的所有符号(全局变量或函数)。

您需要将ASIO库添加到链接步骤,或者通过定义Makefile宏来ASIO_STANDALONE建议,需要在您的某个源中包含ASIO的独立标头文件来编译它。