1

I'm using cmake in VSC on Ubuntu for a simple data cluster algorithm. For this I want to use the already existing Mlpack library. If I try to run my code I receive errors like this

main.cpp:(.text._ZN6mlpack8neighbor14NeighborSearchINS0_19NearestNeighborSortENS_6metric7LMetricILi1ELb0EEEN4arma3MatIdEENS_4tree6KDTreeENS9_15BinarySpaceTreeIS5_NS0_18NeighborSearchStatIS2_EES8_NS_5bound10HRectBoundENS9_13MidpointSplitEE17DualTreeTraverserENSH_19SingleTreeTraverserEE6SearchEmRNS7_ImEERS8_[_ZN6mlpack8neighbor14NeighborSearchINS0_19NearestNeighborSortENS_6metric7LMetricILi1ELb0EEEN4arma3MatIdEENS_4tree6KDTreeENS9_15BinarySpaceTreeIS5_NS0_18NeighborSearchStatIS2_EES8_NS_5bound10HRectBoundENS9_13MidpointSplitEE17DualTreeTraverserENSH_19SingleTreeTraverserEE6SearchEmRNS7_ImEERS8_]+0x6b4): Warnung: undefinierter Verweis auf »mlpack::Log::Info«

This seems to be an error because of false linking to Mlpack. I followed this example Getting Started with mlpack and created my own CmakeLists file

cmake_minimum_required(VERSION 3.8)
set (CMAKE_CXX_STANDARD 14)
project(HelloBoost)

set (VERSION_MAJOR 1)
set (VERSION_MINOR 0)

set(SOURCE main.cpp)

IF (MLPACK_INCLUDE_DIRS)
  # Already in cache, be silent
  SET(MLPACK_FIND_QUIETLY TRUE)
ENDIF (MLPACK_INCLUDE_DIRS)

FIND_PATH(MLPACK_INCLUDE_DIR core.hpp
      PATHS /usr/local/include/mlpack
                /usr/include/mlpack
         )

SET(MLPACK_LIBRARY_DIR NOTFOUND CACHE PATH "The directory where the MLPACK libraries can be found.")
SET(SEARCH_PATHS
    "${MLPACK_INCLUDE_DIR}/../lib"
    "${MLPACK_INCLUDE_DIR}/../../lib"
    "${MLPACK_LIBRARY_DIR}")
FIND_LIBRARY(MLPACK_LIBRARY NAMES mlpack PATHS ${SEARCH_PATHS})

INCLUDE (FindPackageHandleStandardArgs)

FIND_PACKAGE_HANDLE_STANDARD_ARGS(mlpack DEFAULT_MSG MLPACK_LIBRARY MLPACK_INCLUDE_DIR)

IF (MLPACK_FOUND)
   SET(MLPACK_LIBRARIES "${MLPACK_LIBRARY}")
   SET(MLPACK_INCLUDE_DIRS "${MLPACK_INCLUDE_DIR}")
ENDIF (MLPACK_FOUND)




find_package(Armadillo REQUIRED)
find_package(Boost 1.65.1.0 COMPONENTS thread regex system)
if(Boost_FOUND)
  include_directories(${Boost_INCLUDE_DIRS})
  include_directories(${MLPACK_INCLUDE_DIR})
  include_directories(${Armadillo_INCLUDE_DIR})
  add_executable(${PROJECT_NAME} ${SOURCE})
  target_link_libraries(${PROJECT_NAME} ${Boost_THREAD_LIBRARY} ${Boost_REGEX_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${ARMADILLO_LIBRARIES} ${MLPACK_LIBRARY})
endif()

My main.cpp file looks like

#include <iostream>
#include <fstream>
#include <vector>
#include <iterator>
#include <string>
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <mlpack/core.hpp>
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>

using namespace std;
using namespace mlpack;
using namespace mlpack::neighbor;
using namespace mlpack::metric;


void mlModel(string filename) 
{ 
    // Armadillo is a C++ linear algebra library;  
    // mlpack uses its matrix data type. 
    arma::mat data; 

    /* 
    data::Load is used to import data to the mlpack,  
    It takes 3 parameters, 
        1. Filename = Name of the File to be used 
        2. Matrix = Matrix to hold the Data in the File 
        3. fatal = true if you want it to throw an exception 
         if there is an issue 
    */
    data::Load(filename, data, true); 

    /* 
    Create a NeighborSearch model. The parameters of the  
    model are specified with templates: 
        1. Sorting method: "NearestNeighborSort" - This  
        class sorts by increasing distance. 
        2. Distance metric: "ManhattanDistance" - The  
        L1 distance, the sum of absolute distances. 
        3. Pass the reference dataset (the vectors to  
        be searched through) to the constructor. 
     */
    NeighborSearch<NearestNeighborSort, ManhattanDistance> nn(data); 
    // in the above line we trained our model or  
    // fitted the data to the model 
    // now we will predict 

    arma::Mat<size_t> neighbors; // Matrices to hold 
    arma::mat distances; // the results 

    /* 
    Find the nearest neighbors. Arguments are:- 
        1. k = 1, Specify the number of neighbors to find 
        2. Matrices to hold the result, in this case,  
        neighbors and distances 
    */
    nn.Search(1, neighbors, distances); 
    // in the above line we find the nearest neighbor 

    // Print out each neighbor and its distance. 
    for (size_t i = 0; i < neighbors.n_elem; ++i) 
    { 
        std::cout << "Nearest neighbor of point " << i << " is point "
                  << neighbors[i] << " and the distance is " 
                  << distances[i] << ".\n"; 
    } 
} 




int main()
{

    mlModel("../Example Data/collectedData_Protocol1.csv"); 

    return 0;
}

Output off ldd "ProjectName"

linux-vdso.so.1 (0x00007ffcc7d1e000) libmlpack.so.3 => /usr/local/lib/libmlpack.so.3 (0x00007ff8b44d9000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff8b4150000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff8b3f38000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff8b3b47000) libarmadillo.so.8 => /usr/lib/libarmadillo.so.8 (0x00007ff8b393e000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff8b35a0000) libgomp.so.1 => /usr/lib/x86_64-linux-gnu/libgomp.so.1 (0x00007ff8b3371000) /lib64/ld-linux-x86-64.so.2 (0x00007ff8b4b54000) libblas.so.3 => /usr/lib/x86_64-linux-gnu/libblas.so.3 (0x00007ff8b3104000) liblapack.so.3 => /usr/lib/x86_64-linux-gnu/liblapack.so.3 (0x00007ff8b2866000) libarpack.so.2 => /usr/lib/x86_64-linux-gnu/libarpack.so.2 (0x00007ff8b261c000) libsuperlu.so.5 => /usr/lib/x86_64-linux-gnu/libsuperlu.so.5 (0x00007ff8b23ac000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ff8b21a8000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff8b1f89000) libgfortran.so.4 => /usr/lib/x86_64-linux-gnu/libgfortran.so.4 (0x00007ff8b1baa000) libquadmath.so.0 => /usr/lib/x86_64-linux-gnu/libquadmath.so.0 (0x00007ff8b196a000)

Output of nm

nm -D -C /usr/local/lib/libmlpack.so | grep Log::Info000000000044c2e0 B mlpack::Log::Info

Is there something I am missing ? The cmake build does work just fine. Does anyone has a working CmakeList file for using Mlpack wit Cmake on Ubuntu?

I missunderstood the concept of Cmake. I thought running my main.cpp will automatically link the necessary libraries after using Cmake. I know understand that I have to run the CMake Executable in order to get the desired output. This works as expected.

s kop
  • 196
  • 4
  • 18
  • where is mlpack installed on your computer? you specify only two search-paths for it. are you sure that the library really is there? maybe use an `message(FATAL_ERROR "mlpack not found")` to localize your problem. Have you set your "MLPACK_LIBRARY_DIR" when calling cmake? Where is your variable `MLPACK_FOUND` set? It seems like you just forgot to set that. Therefore your other variables are never set. – Tom Mekken Jan 14 '20 at 08:19
  • There is a warning at the beginning of the documentation which you followed: "It is out of date". Maybe its better to follow another documentation. This documentation explains how to build mlpack on ubuntu. https://www.mlpack.org/doc/mlpack-3.0.4/doxygen/build.html – Yunus Temurlenk Jan 14 '20 at 08:28
  • Perhaps I missunderstand the concpet behind the CmakeList.txt as the answer below mentions. The libraries can be found within the path "/usr/lib/" and the include directory is "usr/include/mlpack/" – s kop Jan 14 '20 at 09:53

1 Answers1

4

Just install mlpack in your system and use FindMLPACK.cmake provided in mlpack models repo. Your root CMakeLists.txt should look like this:

cmake_minimum_required(VERSION 3.8)
set (CMAKE_CXX_STANDARD 14)
project(MlpackSample)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package(MLPACK REQUIRED)

add_executable(mlpack_sample main.cpp)
target_link_libraries(mlpack_sample ${MLPACK_LIBRARY})

You just need to put FindMLPACK.cmake file in cmake directory of your project

*
   - CMakeLists.txt
   - main.cpp
   * cmake
      - FindMLPACK.cmake

I paste the content of the file here in case github link expires

#.rst:
# FindMLPACK
# -------------
#
# Find MLPACK
#
# Find the MLPACK C++ library
#
# Using MLPACK::
#
#   find_package(MLPACK REQUIRED)
#   include_directories(${MLPACK_INCLUDE_DIRS})
#   add_executable(foo foo.cc)
#   target_link_libraries(foo ${MLPACK_LIBRARIES})
#
# This module sets the following variables::
#
#   MLPACK_FOUND - set to true if the library is found
#   MLPACK_INCLUDE_DIRS - list of required include directories
#   MLPACK_LIBRARIES - list of libraries to be linked
#   MLPACK_VERSION_MAJOR - major version number
#   MLPACK_VERSION_MINOR - minor version number
#   MLPACK_VERSION_PATCH - patch version number
#   MLPACK_VERSION_STRING - version number as a string (ex: "1.0.4")

include(FindPackageHandleStandardArgs)

# UNIX paths are standard, no need to specify them.
find_library(MLPACK_LIBRARY
  NAMES mlpack
  PATHS "$ENV{ProgramFiles}/mlpack/lib"  "$ENV{ProgramFiles}/mlpack/lib64" "$ENV{ProgramFiles}/mlpack"
)
find_path(MLPACK_INCLUDE_DIR
  NAMES mlpack/core.hpp mlpack/prereqs.hpp
  PATHS "$ENV{ProgramFiles}/mlpack"
)


if(MLPACK_INCLUDE_DIR)
  # Read and parse mlpack version header file for version number
  file(STRINGS "${MLPACK_INCLUDE_DIR}/mlpack/core/util/version.hpp" _mlpack_HEADER_CONTENTS REGEX "#define MLPACK_VERSION_[A-Z]+ ")
  string(REGEX REPLACE ".*#define MLPACK_VERSION_MAJOR ([0-9]+).*" "\\1" MLPACK_VERSION_MAJOR "${_mlpack_HEADER_CONTENTS}")
  string(REGEX REPLACE ".*#define MLPACK_VERSION_MINOR ([0-9]+).*" "\\1" MLPACK_VERSION_MINOR "${_mlpack_HEADER_CONTENTS}")
  string(REGEX REPLACE ".*#define MLPACK_VERSION_PATCH \"?([0-9x]+).*" "\\1" MLPACK_VERSION_PATCH "${_mlpack_HEADER_CONTENTS}")

  unset(_mlpack_HEADER_CONTENTS)

  set(MLPACK_VERSION_STRING "${MLPACK_VERSION_MAJOR}.${MLPACK_VERSION_MINOR}.${MLPACK_VERSION_PATCH}")
endif()

find_package_handle_standard_args(MLPACK
  REQUIRED_VARS MLPACK_LIBRARY MLPACK_INCLUDE_DIR
  VERSION_VAR MLPACK_VERSION_STRING
)

if(MLPACK_FOUND)
  set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIR})
  set(MLPACK_LIBRARIES ${MLPACK_LIBRARY})
endif()

# Hide internal variables
mark_as_advanced(
  MLPACK_INCLUDE_DIR
  MLPACK_LIBRARY
)
pptaszni
  • 5,591
  • 5
  • 27
  • 43
  • I know understand the concept of the FindMLPACK.cmake file specified in Cmake directory. Unfortanetly the additional FindMLPACK.cmake can not find the packaged MLPACKConfig.cmake and mlpack-config.cmake – s kop Jan 14 '20 at 09:30
  • @skop, sorry, I don't understand your comment. What do you mean by "cannot find the packaged `MLPACKConfig.cmake`? File `MLPACKConfig.cmake` is not needed for anything. `FindMLPACK.cmake` is already written in a way that it can find `mlpack` libraries without any additional prerequisites. – pptaszni Jan 14 '20 at 09:36
  • I just found out that the directory of mine was "Cmake" instead of "cmake". Now the build works just fine. But I still receive the same errors if I try to run the main.cpp – s kop Jan 14 '20 at 09:43
  • It means that you didn't install your lib correctly or you have conflicting versions. Verify if your binary is linked with the correct version of libmlpack: `ldd mlpack_sample`. Verify if your `libmlpack` has `mlpack::Log::Info` symbol: `nm -D -C /usr/local/lib/libmlpack.so | grep Log::Info` – pptaszni Jan 14 '20 at 10:02
  • I'm trying to delete all dependencies and rebuilt it clean the manual way. Afterwards I will update the post – s kop Jan 14 '20 at 11:21
  • I rebuilt it completly and receive the same error. I also used your command and got this output: "nm -D -C /usr/local/lib/libmlpack.so | grep Log::Info000000000044c2e0 B mlpack::Log::Info" – s kop Jan 15 '20 at 16:56
  • Good, it means that the lib is installed correctly and it has the required symbol. What is the output of ldd ? – pptaszni Jan 15 '20 at 17:20
  • I can close this issue. I missunderstood the concept of Cmake. I tried to run my main.cpp which is not linked to the libraries. Instead I tried with running my executable and got the desired output. – s kop Jan 16 '20 at 07:53