ros / console_bridge

A ROS-independent package for logging that seamlessly pipes into rosconsole/rosout for ROS-dependent packages.
BSD 3-Clause "New" or "Revised" License
22 stars 62 forks source link

console_bridge-config.cmake.in for cross compiling #41

Closed genemerewether closed 7 years ago

genemerewether commented 7 years ago

My cross-compiling toolchain sets

set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

and console_bridge-config.cmake fails at the find_library line because the console_bridge library is on the host (ROS2 build). Is this a workable solution? Supported since cmake < 2.8

rojkov commented 7 years ago

@genemerewether IIUC you want your cross-compiled target to link to your host's console_bridge. How can that be desirable?

genemerewether commented 7 years ago

@rojkov - Sorry for the misunderstanding... The console_bridge on the host that I refer to is a cross-compiled version and is the correct library to link against. ROS2 builds console_bridge from source and places it in a directory on the host.

All other find_package macros in the build work as they should, but the additional

find_library(onelib ${lib} PATHS "@CMAKE_INSTALL_FULL_LIBDIR@" NO_DEFAULT_PATH )

in console_bridge-config.cmake fails because I've set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)

scpeters commented 7 years ago

@dirk-thomas what do you think?

dirk-thomas commented 7 years ago

I can't say much since I don't have a similar use case like this. I don't understand why the library is not found in the location it has been installed to (CMAKE_INSTALL_FULL_LIBDIR) in the first place.

Doesn't the new argument CMAKE_FIND_ROOT_PATH_BOTH kind of contradict NO_DEFAULT_PATH?

genemerewether commented 7 years ago

The library isn't found because I've set CMAKE_FIND_ROOT_PATH_MODE_LIBRARY to ONLY, which makes sense to me in a cross-compile build. The problem is the nested find_library call: I've got CMAKE_FIND_ROOT_PATH_MODE_PACKAGE set to BOTH, but because console_bridge-config.cmake calls find_library, that call fails and the package is not found.

I rebuilt using NO_CMAKE_FIND_ROOT_PATH instead of CMAKE_FIND_ROOT_PATH_BOTH and the library is found successfully - this seems like the right way here. Without either option, the library is not found.

From CMake find_library documentation:

The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more directories to be prepended to all other search directories. This effectively “re-roots” the entire search under given locations. If NO_CMAKE_FIND_ROOT_PATH is used then CMAKE_FIND_ROOT_PATH will not be used

I interpret this as: even with NO_DEFAULT_PATH, the supplied paths to find_library() will still be re-rooted and the call will fail, unless NO_CMAKE_FIND_ROOT_PATH is also supplied

traversaro commented 7 years ago

A possible more radical approach to solve this problem at the root is to remove all the logic for finding the console_bridge library in the console_bridge-config.cmake.in and substitute it with the more idiomatic approach of exporting console_bridge targets.

A quick sketch of this approach (just edited through the web interface, I did not checked if it is actually working) can be found in https://github.com/ros/console_bridge/compare/master...traversaro:patch-3 .

This change would also simplify transforming console_bridge in a relocatable CMake package.

rojkov commented 7 years ago

@genemerewether BTW what exactly do you use for cross-compiling?

genemerewether commented 7 years ago

@rojkov For reference (I did some digging), NO_CMAKE_FIND_ROOT_PATH matches the way catkin works internally for generating a package_nameConfig.cmake: (https://github.com/ros/catkin/blob/kinetic-devel/cmake/templates/pkgConfig.cmake.in#L128)

I use a Linaro Trusty developer sysroot & toolchain and I define CMAKE_TOOLCHAIN_FILE in the cmake-args to ament. That toolchain file sets the CMAKE_SYSROOT variable.

rojkov commented 7 years ago

Unfortunately I've never used Linaro (I'm using OpenEmbedded for cross-compilation). Can't give any advice on that. But I find it strange too that the tool installs cross-compiled binaries to host instead of sysroot.

Regarding the code in pkgConfig.cmake.in... I had to patch it the other way around to make it work correctly for my use cases. The current logic in upstream makes wrong assumptions about build environment. In my case catkin looks for libraries in locations provided by package dependencies. The list of locations often includes not only paths inside the target sysroot, but also legitimate host paths. If it happens that the native version of a library is installed on hosts then catkin is happily trying to link to that library and fails because of wrong architecture. Here's my custom patch:

diff --git a/cmake/templates/pkgConfig.cmake.in b/cmake/templates/pkgConfig.cmake.in
index d99b811..c692108 100644
--- a/cmake/templates/pkgConfig.cmake.in
+++ b/cmake/templates/pkgConfig.cmake.in
@@ -125,9 +125,9 @@ foreach(library ${libraries})
     foreach(path @PKG_CONFIG_LIB_PATHS@)
       find_library(lib ${library}
         PATHS ${path}
-        NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+        NO_DEFAULT_PATH ONLY_CMAKE_FIND_ROOT_PATH)
       if(lib)
-        set(lib_path ${path})
+        get_filename_component(lib_path ${lib} DIRECTORY)
         break()
       endif()
     endforeach()

The second change for setting lib_path is needed because in case a lib is found in sysroot catkit continues to think that the lib resides in the host's root, not target sysroot. But I'm afraid this patch breaks the use case ROS developers need more than cross-compilation support: having ROS installed in a workspace with the possibility to link to system libraries should they be installed on the host.

scpeters commented 7 years ago

I think this issue was resolved by #45; please re-open if I am mistaken