0

I write a simple c++ code to call some functions defined in ExternalProject_Add() target. When I compile this c++ code, I see some undefined reference errors as follows.

CMakeFiles/okvis_test.dir/main.cpp.o: In function `okvis::cameras::CameraBase::CameraBase(int, int, unsigned long)':
main.cpp:(.text._ZN5okvis7cameras10CameraBaseC2Eiim[_ZN5okvis7cameras10CameraBaseC5Eiim]+0x17): undefined reference to `vtable for okvis::cameras::CameraBase'
CMakeFiles/okvis_test.dir/main.cpp.o: In function `okvis::cameras::CameraBase::~CameraBase()':
main.cpp:(.text._ZN5okvis7cameras10CameraBaseD2Ev[_ZN5okvis7cameras10CameraBaseD5Ev]+0xd): undefined reference to `vtable for okvis::cameras::CameraBase'
CMakeFiles/okvis_test.dir/main.cpp.o:(.rodata._ZTVN5okvis7cameras13PinholeCameraINS0_21EquidistantDistortionEEE[_ZTVN5okvis7cameras13PinholeCameraINS0_21EquidistantDistortionEEE]+0xa0): undefined reference to `okvis::cameras::CameraBase::createRandomImagePoint() const'
CMakeFiles/okvis_test.dir/main.cpp.o:(.rodata._ZTVN5okvis7cameras13PinholeCameraINS0_21EquidistantDistortionEEE[_ZTVN5okvis7cameras13PinholeCameraINS0_21EquidistantDistortionEEE]+0xa8): undefined reference to `okvis::cameras::CameraBase::createRandomVisiblePoint(double, double) const'
CMakeFiles/okvis_test.dir/main.cpp.o:(.rodata._ZTVN5okvis7cameras13PinholeCameraINS0_21EquidistantDistortionEEE[_ZTVN5okvis7cameras13PinholeCameraINS0_21EquidistantDistortionEEE]+0xb0): undefined reference to `okvis::cameras::CameraBase::createRandomVisibleHomogeneousPoint(double, double) const'
CMakeFiles/okvis_test.dir/main.cpp.o:(.rodata._ZTIN5okvis7cameras13PinholeCameraINS0_21EquidistantDistortionEEE[_ZTIN5okvis7cameras13PinholeCameraINS0_21EquidistantDistortionEEE]+0x10): undefined reference to `typeinfo for okvis::cameras::CameraBase'
CMakeFiles/okvis_test.dir/main.cpp.o: In function `okvis::ceres::ReprojectionError<okvis::cameras::PinholeCamera<okvis::cameras::EquidistantDistortion> >::EvaluateWithMinimalJacobians(double const* const*, double*, double**, double**) const':
main.cpp:(.text._ZNK5okvis5ceres17ReprojectionErrorINS_7cameras13PinholeCameraINS2_21EquidistantDistortionEEEE28EvaluateWithMinimalJacobiansEPKPKdPdPSB_SC_[_ZNK5okvis5ceres17ReprojectionErrorINS_7cameras13PinholeCameraINS2_21EquidistantDistortionEEEE28EvaluateWithMinimalJacobiansEPKPKdPdPSB_SC_]+0x937): undefined reference to `okvis::ceres::PoseLocalParameterization::liftJacobian(double const*, double*)'
main.cpp:(.text._ZNK5okvis5ceres17ReprojectionErrorINS_7cameras13PinholeCameraINS2_21EquidistantDistortionEEEE28EvaluateWithMinimalJacobiansEPKPKdPdPSB_SC_[_ZNK5okvis5ceres17ReprojectionErrorINS_7cameras13PinholeCameraINS2_21EquidistantDistortionEEEE28EvaluateWithMinimalJacobiansEPKPKdPdPSB_SC_]+0xe2b): undefined reference to `okvis::ceres::PoseLocalParameterization::liftJacobian(double const*, double*)'
collect2: error: ld returned 1 exit status
CMakeFiles/okvis_test.dir/build.make:148: recipe for target 'okvis_test' failed
make[2]: *** [okvis_test] Error 1
CMakeFiles/Makefile2:96: recipe for target 'CMakeFiles/okvis_test.dir/all' failed
make[1]: *** [CMakeFiles/okvis_test.dir/all] Error 2
Makefile:102: recipe for target 'all' failed
make: *** [all] Error 2

My CMakeLists.txt:

cmake_minimum_required(VERSION 2.8.12)

project(okvis_test)

include(ExternalProject)

####################
# Compile as C++11 and C++14 for CMake versions earlier than 3.1
####################
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -std=c++14")

####################
# Find libraries
####################
find_package(Eigen3 REQUIRED)
find_package(OpenCV REQUIRED)

####################
# Add okvis as an external project
####################
ExternalProject_Add(okvis
  GIT_REPOSITORY    https://github.com/ethz-asl/okvis.git
  GIT_TAG           master
  UPDATE_COMMAND ""
  INSTALL_DIR ${CMAKE_BINARY_DIR}
  CMAKE_ARGS 
    -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_BINARY_DIR}
    -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
    -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} 
    -DBUILD_TESTS:BOOL=OFF
  PREFIX ${CMAKE_CURRENT_BINARY_DIR}/okvis
  BUILD_IN_SOURCE 0
  BUILD_COMMAND make
  INSTALL_COMMAND make install
)

# Make okvis a dependency for other target
ExternalProject_Get_Property(okvis INSTALL_DIR)
set(OKVIS_INCLUDE_DIR ${INSTALL_DIR}/include)
set(OKVIS_LIBS_DIR ${INSTALL_DIR}/lib)
add_library(OKVIS_LIBS STATIC IMPORTED)
set_target_properties(OKVIS_LIBS PROPERTIES IMPORTED_LOCATION ${OKVIS_LIBS_DIR}/libokvis_ceres.a)
set_target_properties(OKVIS_LIBS PROPERTIES IMPORTED_LOCATION ${OKVIS_LIBS_DIR}/libokvis_common.a)
set_target_properties(OKVIS_LIBS PROPERTIES IMPORTED_LOCATION ${OKVIS_LIBS_DIR}/libokvis_cv.a)
set_target_properties(OKVIS_LIBS PROPERTIES IMPORTED_LOCATION ${OKVIS_LIBS_DIR}/libokvis_frontend.a)
set_target_properties(OKVIS_LIBS PROPERTIES IMPORTED_LOCATION ${OKVIS_LIBS_DIR}/libokvis_kinematics.a)
set_target_properties(OKVIS_LIBS PROPERTIES IMPORTED_LOCATION ${OKVIS_LIBS_DIR}/libokvis_matcher.a)
set_target_properties(OKVIS_LIBS PROPERTIES IMPORTED_LOCATION ${OKVIS_LIBS_DIR}/libokvis_multisensor_processing.a)
set_target_properties(OKVIS_LIBS PROPERTIES IMPORTED_LOCATION ${OKVIS_LIBS_DIR}/libokvis_time.a)
set_target_properties(OKVIS_LIBS PROPERTIES IMPORTED_LOCATION ${OKVIS_LIBS_DIR}/libokvis_timing.a)
set_target_properties(OKVIS_LIBS PROPERTIES IMPORTED_LOCATION ${OKVIS_LIBS_DIR}/libokvis_util.a)

# Our main target
add_executable(${PROJECT_NAME} main.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC ${EIGEN3_INCLUDE_DIR} ${OKVIS_INCLUDE_DIR} ${OpenCV_INCLUDE_DIRS})    
target_link_libraries(${PROJECT_NAME} OKVIS_LIBS ${OpenCV_LIBS})
add_dependencies(${PROJECT_NAME} okvis)

My simple c++ code:

#include <Eigen/Dense>

#include <okvis/cameras/EquidistantDistortion.hpp>
#include <okvis/cameras/PinholeCamera.hpp>
#include <okvis/ceres/ReprojectionError.hpp>

int main(int argc, char **argv) {
  using DistortedPinholeCameraGeometry =
      okvis::cameras::PinholeCamera<okvis::cameras::EquidistantDistortion>;

  std::shared_ptr<const DistortedPinholeCameraGeometry> camera_geometry =
      std::static_pointer_cast<const DistortedPinholeCameraGeometry>(
          DistortedPinholeCameraGeometry::createTestObject());
  Eigen::Vector2d kp;
  Eigen::Matrix2d information = Eigen::Matrix2d::Identity();

  okvis::ceres::ReprojectionError<DistortedPinholeCameraGeometry>
      reprojection_error(camera_geometry, 1, kp, information);

  return 0;
}

I don't think the undefined reference to vtable is related to undefined virtual function. The virtual destructor CameraBase class is defined, see https://github.com/ethz-asl/okvis/blob/master/okvis_cv/include/okvis/cameras/CameraBase.hpp#L93 Basically, all virtual functions in CameraBase class are defined or pure virtual.

I have been stuck in this error for hours. Any help or suggestions would be appreciated.

C.Fu
  • 3
  • 1

1 Answers1

0

Target property IMPORTED_LOCATION is intended to contain a single library path. If you want a target to represent several libraries at once, use INTERFACE type for it:

add_library(OKVIS_LIBS INTERFACE)
target_link_libraries(OKVIS_LIBS INTERFACE
    # Whenever one will link with OKVIS_LIBS target,
    # the files below will be linked automatically.
    ${OKVIS_LIBS_DIR}/libokvis_ceres.a
    ${OKVIS_LIBS_DIR}/libokvis_common.a
    ...
    ${OKVIS_LIBS_DIR}/libokvis_util.a
)

For that library you may also specify include directories:

target_include_directories(OKVIS_LIBS INTERFACE ${OKVIS_INCLUDE_DIR})

so all okvis-specific settings can be obtained by simple linking with a library target OKVIS_LIBS.

See also that question about combining "normal" (non-IMPORTED) targets into the single one.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153