在 Linux 上使用 Makefile 编译独立的 ASIO
Compiling standalone ASIO with Makefile on Linux
我正在尝试编译一个小的 c++ 程序,该程序使用 libv4l2 从相机捕获图像,然后使用 asio 通过 UDP 将其发送到另一台计算机。
项目的文件结构为:
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 进行独立编译提出建议?
谢谢!
您遇到错误是因为在 link 步骤中您没有提供生成最终可执行文件所需的所有符号(全局变量或函数)。
您需要将 ASIO 库添加到 link 步骤,或者如您的 Makefile
通过定义 ASIO_STANDALONE
宏建议的那样,需要包含 ASIO 的独立 header 在你的源文件之一中编译它。
独立的 Asio 库是您程序的依赖项。建造时
一个程序,一个人也不会建立依赖关系(除非在特殊情况下
情况)。如果那是必要的,那么构建几乎任何程序都可以
递归地需要大量重建依赖项。
如果你的程序依赖于未打包提供的库
通过你的 Linux 发行版的包管理器然后你必须得到源包
该库并按照其说明在您的系统上构建和安装。
然后你在你的系统满足的(真实)假设上构建你自己的程序
图书馆的依赖。您不重复构建库依赖项
在构建程序中。
standalone 绰号可能已向您建议此库是
意味着在每个使用它的应用程序中重建。它不是。它是
standalone asio
在某种意义上它本身不依赖于任何
boost
库,与 boost::asio
不同,它是从中派生的。 独立
甚至并不意味着该库不依赖于其他库
non-boost 个图书馆。例如。在你的link年龄错误中有一些是
报告 从 asio
函数到 pthread_key_delete
的未定义引用,
这意味着 asio
依赖于 Posix 线程库,libpthread
,
而你没有 linking 它。
独立的 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)
然后:
从其下载源压缩包,例如 asio-1.10.8.tar.bz2
Sourceforge page 和
提取包目录,例如asio-1.10.8
cd
进入包目录和 运行:
$ autoreconf -i
$ ./configure
来自 ./configure
的错误将指示相关性或其他要求
你的系统不满足。修复并重复直到成功。然后运行
$ make
构建包。如果一切顺利,作为 root 运行:
$ make install
安装包。
从开发包或从
源,删除 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
chat-client
/asio-package-dir/src/examples/cpp11/chat
中提供的。只放 chat_client.cpp
chat_message.hpp
在您的 src
文件夹中。
注意注释掉的行:
#LDFLAGS := -L/path/to/your/libv4l2
#LDLIBS := -lv4l2
您指出您的程序需要 link 与库 libv4l2
编辑
但是你自己的 makefile 没有提到任何这样的 linkage。如果你确实需要
link 有了它,那么您至少必须通过以下方式告知 linker 这个事实
取消注释:
LDLIBS := -lv4l2
如果您可以从您的包管理器中安装此库的开发包,请这样做。否则
从源代码构建和安装它。 Debian/Ubuntu不提供此类
一个库包,尽管它们确实提供 libv4l-0
、libv4l-dev
和 libv4l2rds0
。也许您还不确定您需要什么库。
如果您从源代码安装此库并决定将其安装在
一些目录不是 linker 的默认搜索路径之一
(/usr/lib
, /usr/local/lib/
etc...) 然后你还需要通知
linker 它在哪里,通过取消注释:
LDFLAGS := -L/path/to/your/libv4l2
请注意,将 libv4l2
添加到 -lv4l2
的 link 年龄,您
迫使 linker 找到任何其他 libv4l2
反过来取决于。因此,如果您的 linkage 现在因未定义的引用而失败
从 libv4l2
到其他库 libfoo
中的符号,您需要
将 LDLIBS
扩展为:
LDLIBS := -lv4l2 -lfoo
并在必要时告诉 linker 在哪里可以找到 libfoo
:
LDFLAGS := -L/path/to/your/libv4l2 -L/path/to/libfoo
依此类推,直到 linkage 成功。
鉴于此,您可能想知道为什么 asio
库没有类似地计算
在 link 时代。不需要 linker 选项 -lasio
?你自己的 makefile 建议你
相信 linker 需要被告知去哪里寻找这样的图书馆,
它的设置:
LD_FLAGS := -L../../dependencies/asio/asio
虽然已经告诉 linker 去那里寻找图书馆,但你没有告诉它 link
图书馆。
不需要 -lasio
因为这个库 - 通常不典型,但不是
对于 boost
或 boost
-ish 库来说不常见 - 仅是 header 库。
它不提供共享 object 文件 libasio.so
,也不提供任何 object 文件存档
libasio.a
你必须 link 才能得到函数的定义。反而,
它们完全由其 header 文件中的内联定义实现。因此,
他们中的任何一个你需要调用你的程序将被直接编译
如果你只是 #include <asio.hpp>
在制作的源文件中
那些电话。
由于它是一个 header 唯一的库,因此 可以使用它来构建您自己的库
只需提取源代码包,跳过通常的 autotools ./configure;
make;make install
过程,并设置预处理器 -I
选项即可编写程序
在你自己的 makefile 中正确(在 CPPFLAGS
- C PreProcessor Flags 中)
让它找到 asio
headers 在,比方说,
/home/me/downloads/asio/asio-1.10.8
。但如果你的目标是实现
那,你犯了一些错误途中;如果一个包 是 autotooled -
因为 asio
是 - 如果您尝试使用它,则所有赌注都会关闭,除非自动工具提供
安装程序。 正在安装您系统中的库也有
好处是一旦你完成了,你就可以忘记设置特殊的
每个使用它的项目中的编译器和 linker 选项以及
喜欢 /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
。 linker 将在创建它时使其可执行。
我正在尝试编译一个小的 c++ 程序,该程序使用 libv4l2 从相机捕获图像,然后使用 asio 通过 UDP 将其发送到另一台计算机。
项目的文件结构为:
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 进行独立编译提出建议?
谢谢!
您遇到错误是因为在 link 步骤中您没有提供生成最终可执行文件所需的所有符号(全局变量或函数)。
您需要将 ASIO 库添加到 link 步骤,或者如您的 Makefile
通过定义 ASIO_STANDALONE
宏建议的那样,需要包含 ASIO 的独立 header 在你的源文件之一中编译它。
独立的 Asio 库是您程序的依赖项。建造时 一个程序,一个人也不会建立依赖关系(除非在特殊情况下 情况)。如果那是必要的,那么构建几乎任何程序都可以 递归地需要大量重建依赖项。
如果你的程序依赖于未打包提供的库 通过你的 Linux 发行版的包管理器然后你必须得到源包 该库并按照其说明在您的系统上构建和安装。
然后你在你的系统满足的(真实)假设上构建你自己的程序 图书馆的依赖。您不重复构建库依赖项 在构建程序中。
standalone 绰号可能已向您建议此库是
意味着在每个使用它的应用程序中重建。它不是。它是
standalone asio
在某种意义上它本身不依赖于任何
boost
库,与 boost::asio
不同,它是从中派生的。 独立
甚至并不意味着该库不依赖于其他库
non-boost 个图书馆。例如。在你的link年龄错误中有一些是
报告 从 asio
函数到 pthread_key_delete
的未定义引用,
这意味着 asio
依赖于 Posix 线程库,libpthread
,
而你没有 linking 它。
独立的 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)
然后:
从其下载源压缩包,例如 asio-1.10.8.tar.bz2
Sourceforge page 和
提取包目录,例如asio-1.10.8
cd
进入包目录和 运行:
$ autoreconf -i
$ ./configure
来自 ./configure
的错误将指示相关性或其他要求
你的系统不满足。修复并重复直到成功。然后运行
$ make
构建包。如果一切顺利,作为 root 运行:
$ make install
安装包。
从开发包或从
源,删除 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
chat-client
/asio-package-dir/src/examples/cpp11/chat
中提供的。只放 chat_client.cpp
chat_message.hpp
在您的 src
文件夹中。
注意注释掉的行:
#LDFLAGS := -L/path/to/your/libv4l2
#LDLIBS := -lv4l2
您指出您的程序需要 link 与库 libv4l2
编辑
但是你自己的 makefile 没有提到任何这样的 linkage。如果你确实需要
link 有了它,那么您至少必须通过以下方式告知 linker 这个事实
取消注释:
LDLIBS := -lv4l2
如果您可以从您的包管理器中安装此库的开发包,请这样做。否则
从源代码构建和安装它。 Debian/Ubuntu不提供此类
一个库包,尽管它们确实提供 libv4l-0
、libv4l-dev
和 libv4l2rds0
。也许您还不确定您需要什么库。
如果您从源代码安装此库并决定将其安装在
一些目录不是 linker 的默认搜索路径之一
(/usr/lib
, /usr/local/lib/
etc...) 然后你还需要通知
linker 它在哪里,通过取消注释:
LDFLAGS := -L/path/to/your/libv4l2
请注意,将 libv4l2
添加到 -lv4l2
的 link 年龄,您
迫使 linker 找到任何其他 libv4l2
反过来取决于。因此,如果您的 linkage 现在因未定义的引用而失败
从 libv4l2
到其他库 libfoo
中的符号,您需要
将 LDLIBS
扩展为:
LDLIBS := -lv4l2 -lfoo
并在必要时告诉 linker 在哪里可以找到 libfoo
:
LDFLAGS := -L/path/to/your/libv4l2 -L/path/to/libfoo
依此类推,直到 linkage 成功。
鉴于此,您可能想知道为什么 asio
库没有类似地计算
在 link 时代。不需要 linker 选项 -lasio
?你自己的 makefile 建议你
相信 linker 需要被告知去哪里寻找这样的图书馆,
它的设置:
LD_FLAGS := -L../../dependencies/asio/asio
虽然已经告诉 linker 去那里寻找图书馆,但你没有告诉它 link 图书馆。
不需要 -lasio
因为这个库 - 通常不典型,但不是
对于 boost
或 boost
-ish 库来说不常见 - 仅是 header 库。
它不提供共享 object 文件 libasio.so
,也不提供任何 object 文件存档
libasio.a
你必须 link 才能得到函数的定义。反而,
它们完全由其 header 文件中的内联定义实现。因此,
他们中的任何一个你需要调用你的程序将被直接编译
如果你只是 #include <asio.hpp>
在制作的源文件中
那些电话。
由于它是一个 header 唯一的库,因此 可以使用它来构建您自己的库
只需提取源代码包,跳过通常的 autotools ./configure;
make;make install
过程,并设置预处理器 -I
选项即可编写程序
在你自己的 makefile 中正确(在 CPPFLAGS
- C PreProcessor Flags 中)
让它找到 asio
headers 在,比方说,
/home/me/downloads/asio/asio-1.10.8
。但如果你的目标是实现
那,你犯了一些错误途中;如果一个包 是 autotooled -
因为 asio
是 - 如果您尝试使用它,则所有赌注都会关闭,除非自动工具提供
安装程序。 正在安装您系统中的库也有
好处是一旦你完成了,你就可以忘记设置特殊的
每个使用它的项目中的编译器和 linker 选项以及
喜欢 /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
。 linker 将在创建它时使其可执行。