rosmake linker order

Hey folks,

We've run into a very interesting problem. First, where it makes sense, we've decided to make "libraries" of code that are independently testable, and then components that link against those libraries for functionality (either via an isA or hasA relationship to library classes). In one case, our library (cleverly named "Robot") requires KDL, so the library's CMake file goes off and finds the orocos_kdl component and builds against that.

Here's how we do that, in case anyone's curious. Yes, it's hackish, but it seems to work.

/**
# Begin KDL Setup
find_program(ROSPACK_CMD NAMES rospack PATHS /opt/ros/electric/ros/bin)
execute_process(COMMAND ${ROSPACK_CMD} find orocos_kdl RESULT_VARIABLE KDL_FOUND_ERROR OUTPUT_VARIABLE KDL_PATH_UGLY ERROR_VARIABLE KDL_ERROR_STRING)
if (NOT KDL_FOUND_ERROR)
string(STRIP ${KDL_PATH_UGLY} KDL_PATH)
message(STATUS "KDL Component Found.")
message(STATUS " Path: ${KDL_PATH}")
set(KDL_INCLUDE_DIRS ${KDL_PATH}/install_dir/include)
include_directories(${KDL_INCLUDE_DIRS})
message(STATUS " Include: ${KDL_INCLUDE_DIRS}")
set(KDL_LIBRARY_DIRS ${KDL_PATH}/install_dir/lib)
link_directories(${KDL_LIBRARY_DIRS})
message(STATUS " Lib: ${KDL_LIBRARY_DIRS}")
find_library(KDL_LIBRARY NAMES orocos-kdl HINTS ${KDL_LIBRARY_DIRS})
if (NOT KDL_LIBRARY MATCHES "KDL_LIBRARY-NOTFOUND")
set(KDL_LIBRARIES ${KDL_LIBRARY})
message(STATUS " Libraries: ${KDL_LIBRARIES}")
else (NOT KDL_LIBRARY MATCHES "KDL_LIBRARY-NOTFOUND")
message("KDL Library Not Found.")
message(" Something's wrong that defies explanation.")
endif (NOT KDL_LIBRARY MATCHES "KDL_LIBRARY-NOTFOUND")

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${KDL_PATH}/config)
find_package(Eigen3)
include_directories(${EIGEN3_INCLUDE_DIR})
message(STATUS " Eigen: ${EIGEN3_INCLUDE_DIR}")
else (NOT KDL_FOUND_ERROR)
message("KDL Not Found.")
message(" Error: ${KDL_FOUND_ERROR}")
message(" Output: ${KDL_ERROR_STRING}")
message(" Please add /trunk/ThirdParty/components to your ROS_PACKAGE_PATH, and rosmake the orocos_kinematics_dynamics component.")
endif (NOT KDL_FOUND_ERROR)
# End KDL Setup
**/

We can build, link and test the library code without any problems. Now, since our underlying library requires KDL, therefore so does our component (named "RobotKDState"). For the component, though, we're using ROS's component dependency mechanism:

/**
<depend package="orocos_kdl">
**/

And in the component's CMake file, we find where the library is and add it to the target_link_libraries() command.

/**
orocos_component(RobotKDState RobotKDState-component.hpp RobotKDState-component.cpp)
target_link_libraries(RobotKDState Robot ${TINYXML_LIBRARY})
**/

When we go to build the component, though, it fails. The error lead us to believe it was due to a linking issue. So, running rosmake again with verbosity enabled, we see that this is the linking command being used:

/**
/usr/bin/c++ -fPIC -O2 -g -Wl,-rpath,/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib -Wl,-rpath,/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib -pthread -Wl,-z,defs -shared -Wl,-soname,libRobotKDState-gnulinux.so -o ../lib/orocos/gnulinux/libRobotKDState-gnulinux.so CMakeFiles/RobotKDState.dir/RobotKDState-component.cpp.o -L/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib -L/home/user/projects/r2/trunk/code/components/RobotKDState/../../../install/lib -L/opt/ros/electric/stacks/orocos_toolchain/rtt/install/lib -L/usr/local/lib -lorocos-kdl /opt/ros/electric/stacks/orocos_toolchain/rtt/install/lib/liborocos-rtt-gnulinux.so.2.5.0 -lRobot /usr/local/lib/libtinyxml.a -lboost_filesystem-mt -lboost_system-mt -lboost_serialization-mt -lpthread -lrt -ldl -Wl,-rpath,/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib:/home/user/projects/r2/trunk/code/components/RobotKDState/../../../install/lib:/opt/ros/electric/stacks/orocos_toolchain/rtt/install/lib:::::::
**/

Notice how -lorocos_kdl comes before -lRobot? I'm assuming rosmake is putting the manifest.xml dependencies before the CMake dependencies. Trouble is, this fails….. So we tried a different order by hand:

/**
/usr/bin/c++ -fPIC -O2 -g -Wl,-rpath,/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib -Wl,-rpath,/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib -pthread -Wl,-z,defs -shared -Wl,-soname,libRobotKDState-gnulinux.so -o ../lib/orocos/gnulinux/libRobotKDState-gnulinux.so CMakeFiles/RobotKDState.dir/RobotKDState-component.cpp.o -L/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib -L/home/user/projects/r2/trunk/code/components/RobotKDState/../../../install/lib -L/opt/ros/electric/stacks/orocos_toolchain/rtt/install/lib -L/usr/local/lib -lRobot -lorocos-kdl /opt/ros/electric/stacks/orocos_toolchain/rtt/install/lib/liborocos-rtt-gnulinux.so.2.5.0 /usr/local/lib/libtinyxml.a -lboost_filesystem-mt -lboost_system-mt -lboost_serialization-mt -lpthread -lrt -ldl -Wl,-rpath,/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib:/home/user/projects/r2/trunk/code/components/RobotKDState/../../../install/lib:/opt/ros/electric/stacks/orocos_toolchain/rtt/install/lib:::::::
**/

This time, -lRobot is before -lorocos_kdl… and this command links without any trouble. Unfortunately, I'm not aware of any way to define which specific order libraries are linked using either rosmake or CMake.

So, my question is either a) what are we doing wrong with regard to linking against KDL, or b) what are we doing wrong with regard to using libraries?

--
Dustin Gooding
NASA/JSC Robotics

rosmake linker order

Hi Dustin,

On Fri, Feb 10, 2012 at 5:07 PM, Gooding, Dustin R. (JSC-ER411)
<dustin [dot] r [dot] gooding [..] ...> wrote:
> Hey folks,
>
> We've run into a very interesting problem.  First, where it makes sense,
> we've decided to make "libraries" of code that are independently testable,
> and then components that link against those libraries for functionality
> (either via an isA or hasA relationship to library classes).  In one case,
> our library (cleverly named "Robot") requires KDL, so the library's CMake
> file goes off and finds the orocos_kdl component and builds against that.
>
> Here's how we do that, in case anyone's curious.  Yes, it's hackish, but it
> seems to work.
>
> /**
> # Begin KDL Setup
> find_program(ROSPACK_CMD NAMES rospack PATHS /opt/ros/electric/ros/bin)
> execute_process(COMMAND ${ROSPACK_CMD} find orocos_kdl RESULT_VARIABLE
> KDL_FOUND_ERROR OUTPUT_VARIABLE KDL_PATH_UGLY ERROR_VARIABLE
> KDL_ERROR_STRING)
> if (NOT KDL_FOUND_ERROR)
> string(STRIP ${KDL_PATH_UGLY} KDL_PATH)
> message(STATUS "KDL Component Found.")
> message(STATUS "  Path:      ${KDL_PATH}")
> set(KDL_INCLUDE_DIRS ${KDL_PATH}/install_dir/include)
> include_directories(${KDL_INCLUDE_DIRS})
> message(STATUS "  Include:   ${KDL_INCLUDE_DIRS}")
> set(KDL_LIBRARY_DIRS ${KDL_PATH}/install_dir/lib)
> link_directories(${KDL_LIBRARY_DIRS})
> message(STATUS "  Lib:       ${KDL_LIBRARY_DIRS}")
> find_library(KDL_LIBRARY NAMES orocos-kdl HINTS ${KDL_LIBRARY_DIRS})
> if (NOT KDL_LIBRARY MATCHES "KDL_LIBRARY-NOTFOUND")
> set(KDL_LIBRARIES ${KDL_LIBRARY})
> message(STATUS "  Libraries: ${KDL_LIBRARIES}")
> else (NOT KDL_LIBRARY MATCHES "KDL_LIBRARY-NOTFOUND")
> message("KDL Library Not Found.")
> message("  Something's wrong that defies explanation.")
> endif (NOT KDL_LIBRARY MATCHES "KDL_LIBRARY-NOTFOUND")
>
> set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${KDL_PATH}/config)
> find_package(Eigen3)
> include_directories(${EIGEN3_INCLUDE_DIR})
> message(STATUS "  Eigen: ${EIGEN3_INCLUDE_DIR}")
> else (NOT KDL_FOUND_ERROR)
> message("KDL Not Found.")
> message("  Error: ${KDL_FOUND_ERROR}")
> message("  Output: ${KDL_ERROR_STRING}")
> message("  Please add /trunk/ThirdParty/components to your ROS_PACKAGE_PATH,
> and rosmake the orocos_kinematics_dynamics component.")
> endif (NOT KDL_FOUND_ERROR)
> # End KDL Setup
> **/

But are you linking Robot with kdl ??

>
> We can build, link and test the library code without any problems.  Now,
> since our underlying library requires KDL, therefore so does our component
> (named "RobotKDState").  For the component, though, we're using ROS's
> component dependency mechanism:
>
> /**
> <depend package="orocos_kdl">
> **/
>
> And in the component's CMake file, we find where the library is and add it
> to the target_link_libraries() command.
>
> /**
> orocos_component(RobotKDState RobotKDState-component.hpp
> RobotKDState-component.cpp)
> target_link_libraries(RobotKDState Robot ${TINYXML_LIBRARY})
> **/
>
> When we go to build the component, though, it fails.  The error lead us to
> believe it was due to a linking issue.  So, running rosmake again with
> verbosity enabled, we see that this is the linking command being used:
>
> /**
> /usr/bin/c++  -fPIC -O2 -g
> -Wl,-rpath,/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib
> -Wl,-rpath,/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib
> -pthread -Wl,-z,defs   -shared -Wl,-soname,libRobotKDState-gnulinux.so -o
> ../lib/orocos/gnulinux/libRobotKDState-gnulinux.so
> CMakeFiles/RobotKDState.dir/RobotKDState-component.cpp.o
> -L/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib
> -L/home/user/projects/r2/trunk/code/components/RobotKDState/../../../install/lib
> -L/opt/ros/electric/stacks/orocos_toolchain/rtt/install/lib -L/usr/local/lib
> -lorocos-kdl
> /opt/ros/electric/stacks/orocos_toolchain/rtt/install/lib/liborocos-rtt-gnulinux.so.2.5.0 -lRobot /usr/local/lib/libtinyxml.a
> -lboost_filesystem-mt -lboost_system-mt -lboost_serialization-mt -lpthread
> -lrt -ldl
> -Wl,-rpath,/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib:/home/user/projects/r2/trunk/code/components/RobotKDState/../../../install/lib:/opt/ros/electric/stacks/orocos_toolchain/rtt/install/lib:::::::
> **/
>
> Notice how -lorocos_kdl comes before -lRobot?   I'm assuming rosmake is
> putting the manifest.xml dependencies before the CMake dependencies.
>  Trouble is, this fails…..  So we tried a different order by hand:
>
> /**
> /usr/bin/c++  -fPIC -O2 -g
> -Wl,-rpath,/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib
> -Wl,-rpath,/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib
> -pthread -Wl,-z,defs   -shared -Wl,-soname,libRobotKDState-gnulinux.so -o
> ../lib/orocos/gnulinux/libRobotKDState-gnulinux.so
> CMakeFiles/RobotKDState.dir/RobotKDState-component.cpp.o
> -L/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib
> -L/home/user/projects/r2/trunk/code/components/RobotKDState/../../../install/lib
> -L/opt/ros/electric/stacks/orocos_toolchain/rtt/install/lib -L/usr/local/lib
> -lRobot -lorocos-kdl
> /opt/ros/electric/stacks/orocos_toolchain/rtt/install/lib/liborocos-rtt-gnulinux.so.2.5.0
> /usr/local/lib/libtinyxml.a -lboost_filesystem-mt -lboost_system-mt
> -lboost_serialization-mt -lpthread -lrt -ldl
> -Wl,-rpath,/home/user/projects/r2/trunk/ThirdParty/components/orocos_kinematics_dynamics/orocos_kdl/install_dir/lib:/home/user/projects/r2/trunk/code/components/RobotKDState/../../../install/lib:/opt/ros/electric/stacks/orocos_toolchain/rtt/install/lib:::::::
> **/
>
> This time, -lRobot is before -lorocos_kdl…  and this command links without
> any trouble.   Unfortunately, I'm not aware of any way to define which
> specific order libraries are linked using either rosmake or CMake.
>
> So, my question is either a) what are we doing wrong with regard to linking
> against KDL, or b) what are we doing wrong with regard to using libraries?

My guess is that the order is not the real problem, but that Robot
itself is not linked with orocos_kdl, hence leading to undefined
symbols later on by users of Robot. What you can do to check if the
'Robot' library is correctly linked, is by adding the -Wl,-z,defs flag
to the linker options of libRobot.so and see if it still wants to
link it. If not, there's your true error, link libRobot.so with the
kdl library, then come back to your component makefile, where it
probably will be fixed 'automagically'.

Peter