2

I am trying to include a static library that I have created with a static method but getting the following error in runtime when trying to invoke the method:

[ 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_

the static library has 2 files: 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

and 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

the 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}
)

Edit:

Here is the clients 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}
)

What am I missing here?

By the way, I am able to use data from header files in my_commons (enums), the problem occurs when trying to add a cpp file an invoke a static method in it.

Thank you for your help!

Gil404
  • 711
  • 1
  • 8
  • 22
  • It is being compiled successfully. it crashes in runtime. – Gil404 Jun 06 '18 at 08:12
  • Added a missing line... can you try again? Thank you for the help. – Gil404 Jun 06 '18 at 08:21
  • Of course it doesn't work, because you didn't provide any source files for your lib - therefore your project is not even compiled - therefore you have a missing symbol. `add_library(my_commons )`. `set_target_properties(my_commons PROPERTIES LINKER_LANGUAGE CXX)` is a kind of hack, not a good practice. Your install commands are also little hacky. What do you try to achieve at all? – pptaszni Jun 06 '18 at 08:24
  • You say that you have static library, but I don't see where you link with it. – Tsyvarev Jun 06 '18 at 08:24
  • @Ptaq666 my bad with copying it here. added the missing line... – Gil404 Jun 06 '18 at 08:30
  • @Tsyvarev what do you mean? this is the lib I am trying to use... I am including it in a different proj. It might be that I am missing something fundamental here, since it is the first time I am trying to create a C++ static lib, so sorry if I am off track here... – Gil404 Jun 06 '18 at 08:30
  • Oh, so this is `CMakeLists.txt` which **builds the library**, not the one which *uses* it. You build the library with `c++0x` ABI standard. But undefined symbol has `__cxx11` substring, so it seems that a user of the library is compiled with `c++11` standard. And there could be problems, when you try incorporate different ABI standards in one executable. See e.g. this question: https://stackoverflow.com/questions/33394934/converting-std-cxx11string-to-stdstring – Tsyvarev Jun 06 '18 at 09:07
  • @Tsyvarev I added the clients Cmake. looks like it is not the case... – Gil404 Jun 06 '18 at 11:02

1 Answers1

0

Please find below a working example of correct CMake project:

Directory structure:

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

Your source and header files remains unchanged (I only changed *.h to *.hpp --> after all you write in C++, not 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)

Result of the execution:

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

I use newer CMake version to be able to use target_include_directories, because I like this feature. I changed your compiler flags to include C++11 standard, because apparently you use it. I also removed INSTALL CMake rules, because they are irrelevant to the question. Let me know if this answer is OK for you.

=============== EDIT(to answer OP comment)==============

Well, I don't have any problems with embedding this lib in another project structure. The error you got means that your directory structure is incorrect (my_commons dir doesn't exist). Your project tree should look like this:

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

And your project's CMakeLists.txt might look like this:

cmake_minimum_required(VERSION 2.8.11)

project(SomeSimpleProjectUsingMyCommonsLib)

add_subdirectory(MyCommonsLib)

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

Just remember to remove the add_executable instruction from your MyCommonLib/CMakeLists.txt. Also main.cpp should be like this:

#include "ConsoleLog.hpp"

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

Sorry, before I didn't notice that ROSLog is declared as static.

pptaszni
  • 5,591
  • 5
  • 27
  • 43
  • Hi @Ptaq666, thank you for the response! Is it necessary to have a main in a static library? the whole point is to create a class of static methods that I can use in different projects... In addition, since I have more projects with the same compiler flags I do not want to change this one to the newer version for now... – Gil404 Jun 06 '18 at 10:59
  • No no, of course it is not necessary. I only included main executable to prove that the solution is working. You can just embed your `my_commons` lib in your project's `CMakeLists.txt ` by invoking `add_subdirectory`. If you want to install your `my_commons` system-wise and find it with `find_package` - this is more complicated, because you need to create the `my_commonsConfig.cmake`, which complicates your task further. How to do it appropriately is another topic (not that difficult, though). – pptaszni Jun 06 '18 at 11:47
  • The thing is that I am able to use data from Header files in the my_common library. The problem occurs only when adding the cpp with static methods... when tried the add_subdirectory got: CMake Error at my_mission_manager/CMakeLists.txt:27 (add_subdirectory): add_subdirectory given source "my_commons" which is not an existing directory. – Gil404 Jun 06 '18 at 11:53
  • It means `my_commons` directory doesn't exist. I edited the answer and explained how exactly you should embed your lib to the project. – pptaszni Jun 06 '18 at 12:34
  • thank you for all the help... It seems that the hirarchy is correct but it still won't work. However, when I tried moving the code from the cpp file to the header file, everything worked fine. so now I am confused :) – Gil404 Jun 06 '18 at 12:57
  • It's impossible (under normal circumstances). I'm sure that the structure and `CMakeLists` I provided are correct. If the problem exists it is either something with the system configuration (no idea with it might be and I'm not able to help here), or it is some other source file causing the problem. For example template methods implementation. – pptaszni Jun 06 '18 at 13:07
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/172656/discussion-between-ptaq666-and-gil404). – pptaszni Jun 07 '18 at 07:24