Ошибка компоновщика C++ со статической библиотекой

Я пытаюсь включить статическую библиотеку, созданную мной с помощью статического метода, но получаю следующую ошибку во время выполнения при попытке вызвать метод:

[ INFO] [1528271039.635221775]: Initializing nodelet with 4 worker threads. /opt/ros/kinetic/lib/nodelet/nodelet: symbol lookup error:/catkin_ws/devel/lib//libmission_manager_nodelet.so: undefined symbol: _ZN14my_commons10ConsoleLog6ROSLogEiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES6_

статическая библиотека имеет 2 файла: ConsoleLog.h:

#ifndef CONSOLE_LOG_H
#define CONSOLE_LOG_H

#include "ros/ros.h"
namespace my_commons
{
class ConsoleLog
{
  public:
    static void ROSLog(int type, std::string message,std::string taskName);
    static void STDLog(int logType, std::string msg,std::string taskName);
};
} // namespace my_commons
#endif //CONSOLE_LOG_H

и ConsoleLog.cpp:

#include "ConsoleLog.h"
namespace my_commons
{
void ConsoleLog::ROSLog(int type, std::string message, std::string task)
{
    switch (type)
    {
    case (0):
        ROS_DEBUG_STREAM("########## " << task << " DEBUG: " << message << " ##########");
        break;
    case (1):
        ROS_INFO_STREAM("########## " << task << " " << message << " ##########");
        break;
    case (2):
        ROS_WARN_STREAM("##########  " << task << " WARNNING: " << message << " ##########");
        break;
    case (3):
        ROS_ERROR_STREAM("########## " << task << " ERROR: " << message << " ##########");
        break;
    }
}

void ConsoleLog::STDLog(int logType, std::string msg, std::string task)
{
    std::cout << msg << std::endl;
}
} // namespace my_commons

CMakelist.txt:

cmake_minimum_required(VERSION 2.8.3)
project(my_commons)
set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")

find_package(catkin REQUIRED COMPONENTS
roscpp
)

catkin_package(CATKIN_DEPENDS
               INCLUDE_DIRS include)


include_directories(
  ${catkin_INCLUDE_DIRS}
   include/
)
###########
## Build ##
###########


add_library(my_commons
src/ConsoleLog.cpp
)



## Specify libraries to link a library or executable target against

set_target_properties(my_commons PROPERTIES LINKER_LANGUAGE CXX)

target_link_libraries(my_commons
                        ${catkin_LIBRARIES} 
                        ${roscpp_LIBRARIES}                         
)

#add_dependencies(name_of_package_nodelet)

install(DIRECTORY include/
  DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
  FILES_MATCHING PATTERN "*.h"
  PATTERN ".svn" EXCLUDE)

# Install library
install(TARGETS my_commons
  ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
  LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

Редактировать:

Вот клиент CMakeLists.txt:

cmake_minimum_required(VERSION 2.8.3)
project(my_mission_manager)

set(CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}")

find_package(catkin REQUIRED COMPONENTS
    roscpp
    nodelet
  std_msgs 
    my_commons
  message_runtime
  std_srvs
)

catkin_package(
  CATKIN_DEPENDS 
  message_runtime 
  std_msgs 
  my_commons
)

include_directories(
  ${catkin_INCLUDE_DIRS}
   include/
)
###########
## Build ##
###########


add_library(my_mission_manager_nodelet
                src/my_mission_manager_nodelet.cpp
)

## Specify libraries to link a library or executable target against


target_link_libraries( my_mission_manager_nodelet
                        ${catkin_LIBRARIES} 
                        ${roscpp_LIBRARIES}                         
)

#add_dependencies(my_mission_manager_nodelet)


# Install library
install(TARGETS my_mission_manager_nodelet
  ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
  LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

# Install header files
install(DIRECTORY src/
  DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
)

# Install launch files
install(DIRECTORY launch/
  DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch
)

# Install xml files
install(FILES nodelet_plugins.xml
  DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
)

Что мне здесь не хватает?

Кстати, я могу использовать данные из файлов заголовков в my_commons (перечисления), проблема возникает при попытке добавить файл cpp и вызвать в нем статический метод.

Спасибо за помощь!

Он успешно компилируется. он вылетает во время выполнения.

Gil404 06.06.2018 10:12

Добавлена ​​недостающая строка ... вы можете попробовать еще раз? Спасибо вам за помощь.

Gil404 06.06.2018 10:21

Конечно, это не работает, потому что вы не предоставили никаких исходных файлов для своей библиотеки - следовательно, ваш проект даже не скомпилирован - поэтому у вас отсутствует символ. add_library(my_commons <here you should put sth like MyCommons.cpp>). set_target_properties(my_commons PROPERTIES LINKER_LANGUAGE CXX) - это своего рода взлом, а не хорошая практика. Ваши команды установки также немного взломаны. Чего вы вообще пытаетесь достичь?

pptaszni 06.06.2018 10:24

Вы говорите, что у вас есть статическая библиотека, но я не вижу, где вы с ней связываетесь.

Tsyvarev 06.06.2018 10:24

@ Ptaq666 Мне плохо с копированием сюда. добавил недостающую строку ...

Gil404 06.06.2018 10:30

@ Цыварев, что ты имеешь в виду? это библиотека, которую я пытаюсь использовать ... Я включаю ее в другой проект. Возможно, мне здесь не хватает чего-то фундаментального, так как я впервые пытаюсь создать статическую библиотеку C++, так что извините, если я не в курсе ...

Gil404 06.06.2018 10:30

О, так это CMakeLists.txt с строит библиотеку, а не с использует. Вы собираете библиотеку по стандарту c++0x ABI. Но у неопределенного символа есть подстрока __cxx11, поэтому кажется, что пользовательская библиотека скомпилирована по стандарту c++11. И могут возникнуть проблемы, когда вы попытаетесь объединить разные стандарты ABI в один исполняемый файл. См., Например, этот вопрос: stackoverflow.com/questions/33394934/…

Tsyvarev 06.06.2018 11:07

@Tsyvarev Добавил клиентов Cmake. похоже, что это не так ...

Gil404 06.06.2018 13:02
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
8
1 025
1

Ответы 1

Ниже приведен рабочий пример правильного проекта CMake:

Структура каталогов:

ROOT
|
+--inc
|   +--ConsoleLog.hpp
+--src
|   +--ConsoleLog.cpp
|   +--main.cpp
+CMakeLists.txt

Ваш исходный и заголовочный файлы остаются неизменными (я только изменил * .h на * .hpp -> после всего, что вы пишете на C++, а не на C).

main.cpp:

#include "ConsoleLog.hpp"

int main() {
    my_commons::ConsoleLog log;
    log.ROSLog(1, "xxx", "yyy");
    return 0;
}

CMakeLists.txt:

cmake_minimum_required(VERSION 2.8.11)
project(my_commons)
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")

find_package(catkin REQUIRED COMPONENTS roscpp)

add_library(my_commons STATIC src/ConsoleLog.cpp)
target_include_directories(my_commons PUBLIC inc ${roscpp_INCLUDE_DIRS})
target_link_libraries(my_commons ${catkin_LIBRARIES} ${roscpp_LIBRARIES})

add_executable(MyExec src/main.cpp)
target_link_libraries(MyExec my_commons)

Результат казни:

./MyExec 
[ INFO] [1528280295.971205050]: ########## yyy xxx ##########

Я использую более новую версию CMake, чтобы иметь возможность использовать target_include_directories, потому что мне нравится эта функция. Я изменил флаги вашего компилятора, чтобы включить стандарт C++ 11, потому что, видимо, вы его используете. Я также удалил правила INSTALL CMake, потому что они не имеют отношения к вопросу. Сообщите мне, подходит ли вам этот ответ.

=============== РЕДАКТИРОВАТЬ (чтобы ответить на комментарий OP) ==============

Что ж, у меня нет проблем с встраиванием этой библиотеки в другую структуру проекта. Полученная ошибка означает, что ваша структура каталогов неверна (каталог my_commons не существует). Дерево вашего проекта должно выглядеть так:

ROOT
|
+--MyCommonsLib (this is the root of your my_commons library)
|
+--src
|   +--main.cpp
+CMakeLists.txt

А CMakeLists.txt вашего проекта может выглядеть так:

cmake_minimum_required(VERSION 2.8.11)

project(SomeSimpleProjectUsingMyCommonsLib)

add_subdirectory(MyCommonsLib)

add_executable(MyExec src/main.cpp)
target_link_libraries(MyExec my_commons)

Просто не забудьте удалить инструкцию add_executable с вашего MyCommonLib/CMakeLists.txt. Также main.cpp должен быть таким:

#include "ConsoleLog.hpp"

int main() {
    my_commons::ConsoleLog::ROSLog(1, "xxx", "yyy");
    return 0;
}

Извините, раньше я не замечал, что ROSLog объявлен статичным.

Привет @ Ptaq666, спасибо за ответ! Обязательно ли иметь main в статической библиотеке? все дело в том, чтобы создать класс статических методов, которые я могу использовать в разных проектах ... Вдобавок, поскольку у меня есть больше проектов с такими же флагами компилятора, я пока не хочу менять его на более новую версию .. .

Gil404 06.06.2018 12:59

Нет, конечно, не надо. Я включил только основной исполняемый файл, чтобы доказать, что решение работает. Вы можете просто встроить вашу библиотеку my_commons в CMakeLists.txt вашего проекта, вызвав add_subdirectory. Если вы хотите установить свой my_commons системно и найти его с find_package - это более сложно, потому что вам нужно создать my_commonsConfig.cmake, что еще больше усложняет вашу задачу. Как это сделать правильно - другая тема (хотя и не такая уж сложная).

pptaszni 06.06.2018 13:47

Дело в том, что я могу использовать данные из файлов заголовков в библиотеке my_common. Проблема возникает только при добавлении cpp статическими методами ... при попытке add_subdirectory получил: Ошибка CMake в my_mission_manager / CMakeLists.txt: 27 (add_subdirectory): add_subdirectory для данного источника "my_commons", который не является существующим каталогом.

Gil404 06.06.2018 13:53

Это означает, что каталога my_commons не существует. Я отредактировал ответ и объяснил, как именно вы должны встроить свою библиотеку в проект.

pptaszni 06.06.2018 14:34

спасибо за помощь ... Кажется, что иерархия правильная, но все равно не работает. Однако, когда я попытался переместить код из файла cpp в файл заголовка, все сработало нормально. так что теперь я запутался :)

Gil404 06.06.2018 14:57

Это невозможно (при нормальных обстоятельствах). Я уверен, что предоставленная мной структура и CMakeLists верны. Если проблема существует, это либо связано с конфигурацией системы (возможно, я не знаю об этом, и я не могу здесь помочь), либо это какой-то другой исходный файл, вызывающий проблему. Например, реализация шаблонных методов.

pptaszni 06.06.2018 15:07

Позвольте нам продолжить обсуждение в чате.

pptaszni 07.06.2018 09:24

Другие вопросы по теме