简体   繁体   English

仅当我在自己的库中使用犰狳链接错误时,

[英]Armadillo linking error only if I use it in my own library

I'm having some troubles with Armadillo when I use it within my own library. 在自己的库中使用犰狳时,我遇到了一些麻烦。 I installed Armadillo, and I created my own library, which calls the svd_econ method. 我安装了Armadillo,并创建了自己的库,该库调用svd_econ方法。 This is the CMakeList.txt file: 这是CMakeList.txt文件:

cmake_minimum_required (VERSION 2.8.9)
set(PROJECTNAME training_library)
project(${PROJECTNAME})

if (NOT DEFINED ENV{EIGEN_ROOT})
message(FATAL_ERROR "Could not find EIGEN_ROOT environment variable")
endif()

find_package(Armadillo REQUIRED)

include_directories("$ENV{EIGEN_ROOT}")

add_definitions(-g)
add_definitions(-O3)
add_definitions(-DNDEBUG)

include_directories(${ARMADILLO_INCLUDE_DIRS})
include_directories(${PROJECT_SOURCE_DIR}/include)

file(GLOB header include/*.h)
file(GLOB source src/*.cpp)

source_group("Source Files" FILES ${source})
source_group("Header Files" FILES ${header})

add_library(${PROJECTNAME} ${source} ${header})
target_link_libraries(${PROJECTNAME} ${ARMADILLO_LIBRARIES})

This is the header file: 这是头文件:

#include <algorithm>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <armadillo>
#include <Eigen/Dense>
#include <Eigen/SVD>

namespace statistics
{
  bool findPCS(const Eigen::MatrixXd &data, Eigen::VectorXd &eigenvalues, Eigen::MatrixXd &eigenvectors);
}

#endif

and this is the .cpp: 这是.cpp:

#include "statistics.h"

namespace statistics
{

Eigen::MatrixXd convert(const arma::mat &data)
{
  Eigen::MatrixXd res(data.n_rows,data.n_cols);
  for (int i = 0; i < data.n_rows; i++)
  {
    for (int j = 0; j < data.n_cols; j++)
    {
      res(i,j) = data(i,j);
    }
  }
  return res;  
}

arma::mat convert(const Eigen::MatrixXd &data)
{
  arma::mat res(data.rows(),data.cols());
  for (int i = 0; i < data.rows(); i++)
  {
    for (int j = 0; j < data.cols(); j++)
    {
      res(i,j) = data(i,j);
    }
  }
  return res;  
}

Eigen::VectorXd convert(const arma::vec &data)
{
  Eigen::VectorXd res(data.size());
  for (int i = 0; i < data.size(); i++)
  {
    res(i) = data(i);
  }
  return res;  
}

arma::vec convert(const Eigen::VectorXd &data)
{
  arma::vec res(data.size());
  for (int i = 0; i < data.size(); i++)
  {
    res(i) = data(i);
  }
  return res;
}

bool findPCS(const Eigen::MatrixXd &data, Eigen::VectorXd &eigenvalues,  Eigen::MatrixXd &eigenvectors)
{  
  arma::mat arma_mat = convert(data);
  arma::mat U; arma::vec S; arma::mat V;
  arma::svd_econ(U,S,V,arma_mat);    
  eigenvalues = convert(S)/sqrt((double)(data.rows()));    
  eigenvectors = convert(V);

  return true;
}

}

Now, this library compiles without any problems. 现在,该库可以毫无问题地进行编译。 Then, I want to call the findPCS method from another different module called clean_data. 然后,我想从另一个名为clean_data的模块中调用findPCS方法。 The CMakeLists.txt file for it is the following: 的CMakeLists.txt文件如下:

cmake_minimum_required (VERSION 2.8.9)
set(PROJECTNAME clean_data)
project(${PROJECTNAME})

find_package(OpenCV REQUIRED)
find_package(Armadillo REQUIRED)

if (NOT DEFINED ENV{EIGEN_ROOT})
message(FATAL_ERROR "Could not find EIGEN_ROOT environment variable")
endif()

include_directories("$ENV{EIGEN_ROOT}")
include_directories("$ENV{training_INCLUDE}")
link_directories("$ENV{training_LIBS}")

add_definitions(-g)
add_definitions(-O3)
add_definitions(-DNDEBUG)

file(GLOB SOURCES *.c *.cpp)

add_executable(${PROJECTNAME} ${SOURCES})
target_link_libraries(${PROJECTNAME} ${OpenCV_LIBS} ${ARMADILLO_LIBRARIES} training_library)

The main.cpp which calls the findPCS method is as follows: 调用findPCS方法的main.cpp如下:

#include <armadillo>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <ctime>
#include <algorithm>
#include <numeric>
#include <list>
#include <statistics.h>
#include <opencv2/opencv.hpp>
#include <Eigen/Dense>

int main() {

  Eigen::MatrixXd matrix(4,10);
  matrix << 1, 2, 2, 1, 5, 5, 4, 12, 32, 1,
        44, 34, 12, 11, 21, 5, 54, 1, 12, 3,
        33, 128, 112, 126, 3, 3, 2, 12, 1, 54,
        66, 34, 1, 54, 2, 2, 1, 43, 4, 12;
  Eigen::VectorXd eigenval; Eigen::MatrixXd eigenvec;
  statistics::findPCS(matrix,eigenval,eigenvec);

  //arma::mat x = arma::randu<arma::mat>(3,4);
  //arma::mat U; arma::vec S; arma::mat V;
  //arma::svd(U,S,V,x);

  return 0;
}

This code, when I try to compile, gives me this linking error: 这段代码在我尝试编译时给了我这个链接错误:

/home/ilaria/Dev/training_library/build/libtraining_library.a(statistics.cpp.o):     In function `gesdd<double>':
/usr/local/include/armadillo_bits/wrapper_lapack.hpp:571: undefined     reference to `wrapper_dgesdd_'
/home/ilaria/Dev/training_library/build/libtraining_library.a(statistics.cpp.o):     In function `gesvd<double>':
/usr/local/include/armadillo_bits/wrapper_lapack.hpp:506: undefined     reference to `wrapper_dgesvd_'
/usr/local/include/armadillo_bits/wrapper_lapack.hpp:506: undefined reference to `wrapper_dgesvd_'
collect2: error: ld returned 1 exit status
make[2]: *** [clean_data] Error 1
make[1]: *** [CMakeFiles/clean_data.dir/all] Error 2
make: *** [all] Error 2

However, if I decomment the lines that are commented in my main.cpp, the code compiles without any problems, it runs fine and it gives me the right results! 但是,如果我不推荐在main.cpp中注释的行,则代码可以毫无问题地编译,它可以很好地运行,并且可以给我正确的结果! I looked on the Internet, and I couldn't find any useful answer. 我看了看互联网,却找不到任何有用的答案。 I'm using Ubuntu 14.04. 我正在使用Ubuntu 14.04。 I installed armadillo from sources, and lapack, blas and openblas from synaptic. 我从来源安装了犰狳,从突触安装了lapack,blas和openblas。 Can anyone spot a problem anywhere? 谁能在任何地方发现问题? Any help would be much appreciated. 任何帮助将非常感激。

Thanks, Ilaria 谢谢,伊拉里亚

Your problem boils down to library linking order. 您的问题归结为库链接顺序。 I don't know your full linking line, but here is a simplification to illustrate the problem: 我不知道您的完整链接行,但是这里只是一个简化的示例来说明问题:

gcc -o myOutput main.o -l someLibrary -l training_library

Now training_library.a contains references to external symbols: in particular wrapper_dgesvd_ amongst others. 现在training_library.a包含对外部符号的引用:特别是wrapper_dgesvd_等。 These are in fact defined in someLibrary.a (I don't know the actual library name here, so use this moniker to illustrate my point). 这些实际上是在someLibrary.a中定义的(我在这里不知道实际的库名,因此请使用此绰号来说明我的观点)。 However, due to the -l order above they cannot be resolved (the rule is that unresolved symbols on the linker line get processed left-to-right, and only the -l entries appearing to the right of the point where an unresolved symbol was introduced can resolve it). 但是,由于上面的-l顺序,它们无法解析(规则是链接器行上未解析的符号从左到右得到处理,并且只有-l条目出现在未解析符号所在的点的右侧引入即可解决)。

So why does uncommenting the lines in main.cpp help? 那么,为什么取消注释main.cpp的行会有帮助? Because making the calls in the commented lines presumably (under the hood) references those same unresolved symbols (so wrapper_dgesvd_ for example). 因为在注释行中进行调用(大概是在wrapper_dgesvd_ )引用了那些相同的未解析符号(例如, wrapper_dgesvd_ )。 Because these are now introduced to the left of -l someLibrary , this can now be used to resolve them and so they are pulled in. Once pulled in they are now also available for things appearing later on in the command line, ie for the training_library , so your earlier problem goes away. 由于现在将这些引入到-l someLibrary的左侧,因此现在可以使用它们来解析它们,因此可以将它们拉入。一旦拉入,它们现在也可用于以后在命令行中显示的内容,即对于training_library ,因此您之前的问题就消失了。

How to solve this? 如何解决呢? Just a guess, but try changing your CMake line from: 只是一个猜测,不过请尝试从以下方式更改您的CMake行:

target_link_libraries(${PROJECTNAME} ${OpenCV_LIBS} ${ARMADILLO_LIBRARIES} training_library)

To: 至:

target_link_libraries(${PROJECTNAME} training_library ${OpenCV_LIBS} ${ARMADILLO_LIBRARIES})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM