0

Installing nested libraries brings compilation errors.

I try to have a project called CROSP that contains multiple internal libraries, namely : StrainParameterisation, RodProperties, PolynomialRepresentation. These libraries are then linked to one base library : CROSP. This one is the library that is then installed in my usr/local/...

The problem is that when I try to include the library from one external package, I get some errors saying that the compiler did not found the .so file for the internal libraries.

In the following I detail the topology of my project.

The layout of the project is the following:

.
├── cmake
│   ├── cmake_uninstall.cmake.in
│   ├── Config.cmake.in
│   └── installation_module.cmake
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    ├── CROSP
    │   └── cosserat_rod.cpp
    ├── include
    │   └── CROSP
    │       ├── CROSP
    │       │   └── cosserat_rod.hpp
    │       ├── polynomial_representation
    │       │   └── polynomial_representation.hpp
    │       ├── rod_properties
    │       │   └── rod_properties.hpp
    │       └── strain_parameterisation
    │           └── strain_parameterisation.hpp
    ├── polynomial_representation
    │   └── polynomial_representation.cpp
    ├── rod_properties
    │   └── rod_properties.cpp
    └── strain_parameterisation
        └── strain_parameterisation.cpp

The CMakeLists are :

Top level CMakeLists

cmake_minimum_required(VERSION 3.22 FATAL_ERROR)

project(CROSP LANGUAGES CXX VERSION 2.0)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)



find_package(Eigen3 3.4 NO_MODULE REQUIRED)



#   External utilities to configure the package
include(GNUInstallDirs)
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
set(LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})


#   Give different names for debug and Release
set(CMAKE_RELEASE_POSTFIX "")
set(CMAKE_DEBUG_POSTFIX "-debug")


add_subdirectory(src)


#   Install the library using the default routine
include(cmake/installation_module.cmake)

The installation_module.cmake

#   Generates ${PROJECT_NAME}Config.cmake file to use our package in other projects
include(CMakePackageConfigHelpers)
configure_package_config_file(
  cmake/Config.cmake.in # input template
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake # output config file
  INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake # where to put the config file during install
  PATH_VARS INCLUDE_INSTALL_DIR LIB_INSTALL_DIR # paths to be used
  NO_CHECK_REQUIRED_COMPONENTS_MACRO
)

#   Generates a config file to ensure that URL's version is checked when importing it
write_basic_package_version_file(
  ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
  VERSION ${PROJECT_VERSION}
  COMPATIBILITY SameMajorVersion
)



#   When running make install, config files should be copied as well
install(
  FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
        ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
  DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}/cmake
)

#   Add the possibility tu run 'make uninstall' to remove files added via 'make install'
configure_file(
  cmake/cmake_uninstall.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake
  IMMEDIATE @ONLY
)
add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")

The Config.cmake.in module :

@PACKAGE_INIT@

set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)

set_and_check(@PROJECT_NAME@_INCLUDE_DIRS @PACKAGE_INCLUDE_INSTALL_DIR@/@PROJECT_NAME@)
set_and_check(@PROJECT_NAME@_LIBRARY_DIR @PACKAGE_LIB_INSTALL_DIR@)
find_library(@PROJECT_NAME@_LIBRARIES NAMES @PROJECT_NAME@ PATHS ${@PROJECT_NAME@_LIBRARY_DIR} NO_DEFAULT_PATH)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(@PROJECT_NAME@ DEFAULT_MSG @PROJECT_NAME@_INCLUDE_DIRS @PROJECT_NAME@_LIBRARIES)

Then We have the CMakeLists in src

include_directories(include)

add_library(PolynomialRepresentation SHARED
    include/${PROJECT_NAME}/polynomial_representation/polynomial_representation.hpp
    polynomial_representation/polynomial_representation.cpp
)
target_link_libraries(PolynomialRepresentation
    PRIVATE
        Eigen3::Eigen
)
target_compile_options(PolynomialRepresentation
    PRIVATE
        -Wall
        -Wextra
)

add_library(RodProperties SHARED
    include/${PROJECT_NAME}/rod_properties/rod_properties.hpp
    rod_properties/rod_properties.cpp
)
target_link_libraries(RodProperties
    PRIVATE
        Eigen3::Eigen
        PolynomialRepresentation
)
target_compile_options(RodProperties
    PRIVATE
        -Wall
        -Wextra
)

add_library(StrainParameterisation SHARED
        include/${PROJECT_NAME}/strain_parameterisation/strain_parameterisation.hpp
        strain_parameterisation/strain_parameterisation.cpp
)
target_link_libraries(StrainParameterisation
    PRIVATE
        Eigen3::Eigen
        PolynomialRepresentation
)
target_compile_options(RodProperties
    PRIVATE
        -Wall
        -Wextra
)





add_library(${PROJECT_NAME} SHARED
                            include/${PROJECT_NAME}/${PROJECT_NAME}/cosserat_rod.hpp
                            ${PROJECT_NAME}/cosserat_rod.cpp
)
target_link_libraries(${PROJECT_NAME}
    PRIVATE
        Eigen3::Eigen
    PUBLIC
        StrainParameterisation
        RodProperties
        PolynomialRepresentation
)
target_compile_options(RodProperties
    PRIVATE
        -Werror
        -Wall
        -Wextra
)



add_executable(main main.cpp)
target_link_libraries(main ${PROJECT_NAME} Eigen3::Eigen)


install(
    TARGETS
        ${PROJECT_NAME}
    DESTINATION
        ${CMAKE_INSTALL_LIBDIR}
)
install(DIRECTORY include/${PROJECT_NAME}
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)



I can run and install this library. The following code compiles and runs fine.

#include "CROSP/CROSP/cosserat_rod.hpp"


int main(int argc, char *argv[])
{

    ::CROSP::polynomial_representation::PolynomialRepresentation poly(5);

    ::CROSP::rod_properties::MaterialProperties material(200, 100, 10);

    ::CROSP::CosseratRod rod(poly, material);

    ::CROSP::CosseratRod rod2(15);

    ::CROSP::CosseratRod rod3;
    return 0;
}

The installation in my usr folder has the following layout

usr
└── local
    ├── include
    │   └── CROSP
    │       ├── CROSP
    │       │   └── cosserat_rod.hpp
    │       ├── polynomial_representation
    │       │   └── polynomial_representation.hpp
    │       ├── rod_properties
    │       │   └── rod_properties.hpp
    │       └── strain_parameterisation
    │           └── strain_parameterisation.hpp
    ├── lib
    │   ├── libCROSP-debug.so
    │   └── libCROSP.so
    └── share
        └── CROSP
            └── cmake
                ├── CROSPConfig.cmake
                └── CROSPConfigVersion.cmake

From another project, I can include the library without problem. Here there is an example

cmake_minimum_required(VERSION 3.5)

project(test_crosp_library LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)


find_package(CROSP REQUIRED)
find_package(Eigen3 3.4 NO_MODULE REQUIRED)


add_executable(test_crosp_library main.cpp)
target_link_libraries(test_crosp_library
    PUBLIC
        CROSP
        Eigen3::Eigen
)


And the main.cpp looks like this

#include "CROSP/CROSP/cosserat_rod.hpp"


int main()
{
    ::CROSP::CosseratRod rod;   //  errors
    return 0;
}

I get the following errors

[ 50%] Linking CXX executable test_crosp_library
/usr/bin/ld: warning: libStrainParameterisation.so, needed by /usr/local/lib/libCROSP.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libRodProperties.so, needed by /usr/local/lib/libCROSP.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: /usr/local/lib/libCROSP.so: undefined reference to `LieAlgebra::SE3Pose::getRotationMatrix() const'
/usr/bin/ld: /usr/local/lib/libCROSP.so: undefined reference to `CROSP::strain_parameterisation::StrainParameterisation::StrainParameterisation(CROSP::polynomial_representation::PolynomialRepresentation, unsigned int)'
/usr/bin/ld: /usr/local/lib/libCROSP.so: undefined reference to `CROSP::strain_parameterisation::StrainParameterisation::StrainParameterisation(CROSP::polynomial_representation::PolynomialRepresentation, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, unsigned int)'
/usr/bin/ld: /usr/local/lib/libCROSP.so: undefined reference to `CROSP::rod_properties::RodProperties::RodProperties(CROSP::polynomial_representation::PolynomialRepresentation)'
/usr/bin/ld: /usr/local/lib/libCROSP.so: undefined reference to `CROSP::strain_parameterisation::StrainParameterisation::updateStacks(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/test_crosp_library.dir/build.make:97: test_crosp_library] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/test_crosp_library.dir/all] Error 2
make: *** [Makefile:91: all] Error 2


Can you tell what is wrong ?

Moreover, I would like to know if I can use the INTERFACE functionality in order to install the internal libraries in my usr/local with namespaces.

So the CMakeLists.txt of a package using CROSP will be:

find_package(CROSP REQUIRED)

add_executable(main main.cpp)
target_link_libraries(main 
      CROSP::MaterialProperties
      CROSP::StrainParameterisation
)
  • "when I try to include the library from one external package, I get some errors saying that the compiler did not found the .so file for the internal libraries." - You don't install internal libraries, so how do you expect your main library is usable? BTW why do you use manually-written Config file with `find_library` instead of Config files automatically generated by CMake with `install(EXPORT)`? That approach detects missed libraries at configuration stage, and is able to add "namespace" for installed targets. https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#creating-packages – Tsyvarev Sep 26 '22 at 10:15
  • @Tsyvarev Hello, thank you for you feedback ! I tried for quite some time to make it work with the your suggestion and the cmake documentation. However, I really do not find a way to make it work with the current layout of my project... I think I'm missing something... Can you provide a working example of your suggestion ? I would really appreciate it, as I'm quite stuck at this point... – Andrea Gotelli Oct 07 '22 at 17:06
  • "Can you provide a working example of your suggestion?" - I cannot check "working" property of any example because I don't have libraries which you are using. I don't understand what do you want to see in that example? As I said above, "not found" warnings should be solved by installing the internal libraries. A library is installed with the same `install(TARGET)` command as you use for the `CROSP` library. – Tsyvarev Oct 07 '22 at 20:46

0 Answers0