2017-02-03 5 views
0

Я пытаюсь скомпилировать небольшую программу на C++, которая захватывает изображение с камеры с помощью libv4l2, а затем отправляет его по UDP на отдельный компьютер с использованием asio.Компиляция автономного ASIO с Makefile в Linux

Файл структура проекта:

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 [email protected] $^ 

obj/%.o: src/%.cpp 
    $(CC) $(CC_FLAGS) -c -o [email protected] $< 

Однако, когда я пытаюсь скомпилировать это, мой компилятор плюет на десятки undefined reference ошибок для функций ASIO:

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()' 

Я предполагаю, что проблема заключается в том, что мой Make файл все еще неправильно находит ASIO и пытается скомпилировать его отдельно. Тем не менее, я не совсем уверен, что еще попробовать - есть ли у кого-нибудь еще предложения по тому, что мне нужно сделать, чтобы ASIO мог самостоятельно составлять Makefile?

спасибо!

+0

Кажется, вы указали путь к библиотеке, но не указали lib для ссылки/загрузки на последнем шаге. – Shiping

+0

Поскольку автономный заголовок только для заголовка, он не создает .lib - поэтому я думал, что ему не нужно ссылаться на библиотеку? Как мне связать/загрузить его на последнем шаге? –

+0

Что в ../../dependencies/asio/asio? вы использовали -L, это означает, что вы сказали ld искать нужную библиотеку там, но вам все равно нужно сообщить ld, какую библиотеку вам нужно связать. – Shiping

ответ

2

Автономная библиотека Asio - это зависимость вашей программы. При построении программы одна из них также не создает зависимостей (если только в исключительных случаях ). Если бы это было необходимо, то при построении почти любой программы рекурсивно требовало бы огромных количеств зависимостей перестройки.

Если ваша программа имеет зависимость от библиотеки, которая не предусмотрена упакованным менеджера пакетов вашего Linux дистрибутива, то вы должны получить пакет источника этой библиотеки и построить и установить на вашей системе в соответствии с его инструкциями.

Затем вы создаете свою собственную программу на основе (истинного) предположения о том, что ваша система удовлетворяет библиотечной зависимости. Вы не будете повторять построение библиотечной зависимости в здании вашей программы.

автономной клички мог бы предложил вам, что эта библиотека означает быть перестроено в каждом приложении, которое использует его. Это не. Это автономный asio в том смысле, что он сам не зависит от каких-либо boost libaries, в отличие от boost::asio, из которого получено. Standalone даже не подразумевает, что библиотека не имеет зависимостей от других небудиционных библиотек. Например. среди ваших ошибок сцепления некоторые, что отчета неопределенные ссылки изasio функций pthread_key_delete, что означает asio зависит от Posix нити библиотеки, libpthread, и вы не связывая его.

Библиотека Standalone 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 

Чтобы создать пакет. Если все хорошо, в корневой перспективе:

$ make install 

для установки пакета.

После того, как вы установили автономный Asio либо из пакета DEV или из источника, удалить project/dependencies/asio и строить свою программу в project/cpp/cpp_client с Makefile, как это:

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 [email protected] $^ $(LDLIBS) 

obj/%.o: src/%.cpp | obj 
    $(CXX) $(CXXFLAGS) -c -o [email protected] $< 

obj: 
    mkdir -p [email protected] 

clean: 
    rm -f obj/* client 

Для репетицию, я предлагаю сначала использовать этот makefile для создания чата-клиента asio , который представлен в /asio-package-dir/src/examples/cpp11/chat. Поместите только chat_client.cpp chat_message.hpp в папку для вашего src.

Обратите внимание на закомментированы линии:

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

Вы указали, что ваша программа должна быть связана с библиотекой libv4l2 , но собственный Makefile не говоря уже о какой-либо такой связи.Если вам нужно связи с ним, то вы должны по крайней мере сообщить компоновщик этого факта раскомментировав:

LDLIBS := -lv4l2 

Если вы можете установить Dev пакет этой библиотеки из менеджера пакетов, сделайте это. В противном случае создайте и установите его из источника. Debian/Ubuntu не предоставляет такой пакет , хотя они предоставляют libv4l-0, libv4l-dev и libv4l2rds0. Возможно, вы точно не знаете, какую библиотеку вам нужно.

Если установить эту библиотеку из источника и решили установить его в некоторый каталог, который не один из поиска по умолчанию путей компоновщика (/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 не требуется, потому что эта библиотека - нетипично в целом, но не нетипично для boost или boost -ish библиотек - это только заголовок библиотеки. Он не предоставляет файл общих объектов libasio.so, ни архив объектных файлов , который вы должны связывать, чтобы получить определения функций. Вместо этого, они полностью реализуются встроенными определениями в своих заголовочных файлах. Таким образом, любой из них, который вам нужно вызвать в вашей программе, будет скомпилирован прямо в него , если вы просто #include <asio.hpp> в источнике (-ах), который делает этими вызовами.

Поскольку это только заголовок библиотека, она является можно использовать для создания собственных программ просто путем извлечения пакета источника, пропуская обычный Autotools ./configure; make;make install процедуры и настройке препроцессора -I опции в собственном makefile правильно (в CPPFLAGS - C PreProcessor Flags) , чтобы найти заголовки asio, скажем, /home/me/downloads/asio/asio-1.10.8. Но если вы стремились достичь , вы допустили ошибку (-и) по маршруту; и если пакет - - автоопределение - - asio - тогда все ставки отключены, если вы попытаетесь использовать его, за исключением случаев, предусмотренных автоустановкой . Установка библиотеки в системе также имеет потенциал роста, что, как только вы сделали это, вы можете забыть о настройке своеобразных опций компилятора и компоновщика в каждом проекте, который использует его и подобное /home/me/downloads/asio/asio-1.10.8 не нужно становиться a светильник вашего домашнего каталога.

Ваш make-файл и то, что вы говорите о его проблемах, говорит о том, что вы пытаетесь использовать GCC и GNU Make by догадки, проб и ошибок. Вот a fairly good starter tutorial in the use of those tools. Для авторитетному документации, здесь the GNU Make manual и здесь the GCC manual

Кстати, в Linux исполняемый файл отличается просто его атрибутами файла и не имеющий .exe расширение, как в Windows, так ваша целевая программа может и нормально будет называться просто client, а не client.exe. Компилятор сделает его исполняемым, когда он его создаст.

+0

Ничего себе! Большое вам спасибо за тщательный ответ; это было очень полезно, увидев пару мест, где я поступил неправильно. Тем не менее, моя цель состояла в том, чтобы скомпилировать asio как проект только для заголовка, разместив заголовки. Вы сказали, что я допустил некоторые ошибки в пути - что бы это было? –

+0

@nathanlachenmyer Добро пожаловать! Что касается того, что пошло не так с вашей инсталляционной настройкой 'asio', , я не могу сказать, что сама эта настройка не была, + источник' клиент' , который вы на самом деле пытались построить. Если я создам пример 'chat_client' с , нет asio install & just pass' -I/path/to/asio/download/dir' до компилятор & пренебрежение '-pthread', ссылка не работает с неопределенным refs отличается от вашего , все символы 'pthread'; с '-pthread' преуспевает. Различия, которые делают разницу, не в моих глазах; , но установка lib сделает все правильно и закрепит его от любого случайного повреждения . –

+0

меня раздражает, когда такие ответы скрываются в подземельях SO. Жаль, что я мог бы поддержать 100 раз – smac89

0

Вы получаете ошибки, потому что на этапе ссылки вы не указали все символы (глобальные переменные или функции), необходимые для создания окончательного исполняемого файла.

Вам необходимо либо добавить библиотеку ASIO на шаг ссылки, либо, как предлагает ваш Makefile макрос ASIO_STANDALONE, вам необходимо включить автономный заголовок ASIO в один из ваших исходных файлов для его компиляции.

Смежные вопросы