Linking Issue with Emscripten and Ceres-Solver: "undefined symbol: typeinfo for ceres::CostFunction"

109 Views Asked by At

I'm working on a project that uses the Ceres-Solver library. The project compiles successfully when using a regular CMake setup. However, when I try to compile it using the Emscripten compiler, I run into a linking issue.

The error I get is:

  em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libamd.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libamd.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libblas.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libblas.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libbtf.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libbtf.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libcamd.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libcamd.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libccolamd.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libccolamd.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libceres.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libceres.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libcholmod.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libcholmod.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libcolamd.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libcolamd.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libcxsparse.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libcxsparse.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libgflags.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libgflags.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libgpuqrengine.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libgpuqrengine.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libspex.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libspex.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libspqr.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libspqr.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libklu.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libklu.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libklu_cholmod.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libklu_cholmod.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libldl.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libldl.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libmongoose.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libmongoose.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/librbio.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/librbio.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libspqr_cuda.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libspqr_cuda.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/liblapack.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/liblapack.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libsuitesparseconfig.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libsuitesparseconfig.a: adding index [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libumfpack.a: archive is missing an index; Use emar when creating libraries to ensure an index is created [-Wemcc]
    em++: warning: /rnd_ceres-solver/thirdparty/build/install/lib/libumfpack.a: adding index [-Wemcc]
    wasm-ld: error: CMakeFiles/simple_bundle_adjuster.dir/bundle_adjuster.cc.o: undefined symbol: typeinfo for ceres::CostFunction

Also, how to ensure using emscripten that archives are created by emar rather than the system ar tool?

Steps to Reproduce:

  1. Build ceres-solver from the source with all dependent libraries also from the source using emscripten compiler only. Ceres Solver Installation

  2. I am now trying to build it using Emscripten with the following shell script that sets up the Emscripten environment and executes emcmake and make:

    #!/bin/bash
    echo "Setting up emsdk environment..."
    source ~/emsdk/emsdk_env.sh
    
    # Specify the directory where you want to create the build folder
    build_dir=build
    
    # Ensure we're in the same directory as the CMakeLists.txt file
    script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
    
    # Create the build directory if it doesn't exist
    mkdir -p "${script_dir}/${build_dir}"
    
    # Navigate into the build directory
    cd "${script_dir}/${build_dir}" || { echo "ERROR: Failed to navigate into build directory. Exiting..."; exit 1; }
    
    echo "Running emcmake and make..."
    emcmake cmake .. ; time make
    

CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)

project(simple_bundle_adjuster)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_definitions(-Wc++17-narrowing)

function(list_transform_prepend var prefix)
    set(temp "")
    foreach(f ${${var}})
        list(APPEND temp "${prefix}${f}")
    endforeach()
    set(${var} "${temp}" PARENT_SCOPE)
endfunction()

# Set the path to local packages
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/thirdparty/build/install")

include_directories("${CMAKE_SOURCE_DIR}/thirdparty/build/install/include")
include_directories("${CMAKE_SOURCE_DIR}/thirdparty/build/install/share/eigen3/cmake")
include_directories("${CMAKE_SOURCE_DIR}/thirdparty/build/install/include/eigen3")
# Manually specify the directory of Eigen3
set(Eigen3_DIR "${CMAKE_SOURCE_DIR}/thirdparty/build/install/share/eigen3/cmake")
# find_package(Eigen3 REQUIRED PATHS "${CMAKE_SOURCE_DIR}/thirdparty/build/install/share/eigen3/cmake")

set(AMDL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libamd.a")
set(BLASL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libblas.a")
set(BTF "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libbtf.a")
set(CAMDL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libcamd.a")
set(CCOLAMDL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libccolamd.a")
set(CERESL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libceres.a")
set(CHOLMODL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libcholmod.a")
set(COLAMDL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libcolamd.a")
set(CXSPARSEL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libcxsparse.a")
set(GFLAGS "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libgflags.a")
# set(GLOG "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libglog.dylib")
set(GPUQRENGINEL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libgpuqrengine.a")
set(SPEXL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libspex.a")
set(SPQRL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libspqr.a")
set(KLUL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libklu.a")
set(KLU_CHOLMODL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libklu_cholmod.a")
set(LDL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libldl.a")
set(MONGOOSE "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libmongoose.a")
set(RBIOL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/librbio.a")
set(SPQR_CUDA "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libspqr_cuda.a")
set(LAPACKL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/liblapack.a")
set(SuiteSparse_DEPENDENCY  "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libsuitesparseconfig.a")
set(UMFL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libumfpack.a")
set(CERESL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libceres.a")
# set(GRAPHBLASL "${CMAKE_SOURCE_DIR}/thirdparty/build/install/lib/libgraphblas.dylib")
# test

set(CERES_SOLVER_DEPENDENCIESL ${AMDL} ${BLASL} ${BTF} ${CAMDL} ${CCOLAMDL} ${CERESL} ${CHOLMODL} ${COLAMDL} ${CXSPARSEL} ${GFLAGS} ${GPUQRENGINEL} ${SPEXL} ${SPQRL} ${KLUL} ${KLU_CHOLMODL} ${LDL} ${MONGOOSE} ${RBIOL} ${SPQR_CUDA} ${LAPACKL} ${SuiteSparse_DEPENDENCY} ${UMFL} ${GRAPHBLASL})
list_transform_prepend(CERES_SOLVER_DEPENDENCIESL "") 
# set(CERES_SOLVER ${CERES_SOLVER_DEPENDENCIESL})

# Add source files
add_executable(simple_bundle_adjuster bundle_adjuster.cc)

# Link the libraries
target_link_libraries(simple_bundle_adjuster ${CERES_SOLVER_DEPENDENCIESL})

This results in the linking error.

  • I've verified that all necessary libraries are included in the linking process.
  • I suspect that I need to pass some Emscripten compiler flags, but I'm not sure which ones would resolve this issue.

Relevant .cc code sinppet:

#include "ceres/ceres.h"

int main() {

    BALProblem bal_problem;

    if (!bal_problem.LoadData()) {
        std::cerr << "ERROR: unable to load data " << "\n";
        return 1;
    }

    const double* observations = bal_problem.observations();
    // Create residuals for each observation in the bundle adjustment problem. The
    // parameters for cameras and points are added automatically.
    ceres::Problem problem;
    for (int i = 0; i < bal_problem.num_observations(); ++i) {
        // Each Residual block takes a point and a camera as input and outputs a 2
        // dimensional residual. Internally, the cost function stores the observed
        // image location and compares the reprojection against the observation.
        ceres::CostFunction* cost_function =
            SnavelyReprojectionError::Create(observations[2 * i + 0],
                observations[2 * i + 1]);

        //ceres::LossFunction* loss_function = new ceres::TukeyLoss(10.0);      // MAH Robust method

        problem.AddResidualBlock(cost_function,
             NULL  /*squared loss */,
            bal_problem.mutable_camera_for_observation(i),
            bal_problem.mutable_point_for_observation(i));
            
    }
 }

I would appreciate any suggestions to resolve this issue. Thank you.

0

There are 0 best solutions below