mardi 5 avril 2022

Including header files in `CMakeLists.txt` [duplicate]

I have a relatively simple question about building a C++ project with cmake. I'm unable properly import functions from a source file into another. I have a minimum working example in a project folder structured as follows.

.
├── CMakeLists.txt
├── README.md
├── include
│   └── print.hpp
└── src
    ├── main.cpp
    └── print.cpp

I have two files in src/: main.cpp and print.cpp. The latter contains functions to print the contents of a vector, and main.cpp tries to use these functions to print out the elements of some example vector. My CMakeLists.txt is specified as follows.

cmake_minimum_required(VERSION 3.0.0)
set(CMAKE_CXX_COMPILER "g++-11")
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

project(tests VERSION 1.0)

set(SOURCE_FILES
    src/print.cpp
)

add_executable(tests
    src/main.cpp
    ${SOURCE_FILES}
)

target_link_libraries (tests Eigen3::Eigen)
target_include_directories(tests PUBLIC include)

set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

The main.cpp file contains:

#include <vector>
#include <numeric>
#include <algorithm>
#include <iostream>
#include "print.hpp"
using namespace std;

int main() {
    cout << "Testing C++ functions." << endl;

    vector<vector<double>> weights(3);
    weights[0] = {0.1, 0.9};
    weights[1] = {0.3, 0.4, 0.3};
    weights[2] = {0.2, 0.1, 0.5, 0.2};

    vector<int> sizes(weights.size());
    int i;
    for (i = 0; i < weights.size(); i ++)
        sizes[i] = weights[i].size();

    print_vector2D<vector<vector<double>>>(weights, "Weights");
    print_vector1D<vector<int>>(sizes, "Sizes");

    return 0;
}

and print.cpp contains:

#include <string>
#include <iostream>
using namespace std;

template <class generic_type>
void print_vector2D(generic_type vect, string name){
    // Print the contents of a Vector.
    cout << name << endl;
    int i, j;
    for (i = 0; i < vect.size(); i ++){
        cout << vect[i][0];
        for (j = 1; j < vect[i].size(); j ++)
            cout << " " << vect[i][j];
        cout << endl;
    }
}

template <class generic_type>
void print_vector1D(generic_type vect, string name){
    // Print the contents of a Vector.
    cout << name << endl;
    int i;
    cout << vect[0];
    for (i = 1; i < vect.size(); i ++)
        cout << " " << vect[i];
    cout << endl;
}

Finally, print.hpp has the function headers.

#ifndef PRINT_HPP
#define PRINT_HPP PRINT_HPP

#include <string>
using namespace std;

// Print the contents of a Vector.
template <class generic_type>
void print_vector2D(generic_type vect, string name);

// Print the contents of a Vector.
template <class generic_type>
void print_vector1D(generic_type vect, string name);

#endif

When I build the project using cmake following the four steps below:

  1. mkdir -p build/
  2. cmake .
  3. cd build
  4. cmake --build ../

I get an error that reflects missing links to the print functions called from main.

(base) pavithran@MBA-FVFGJ3FGQ6LR build % cmake --build ../
Consolidate compiler generated dependencies of target tests
[ 33%] Building CXX object CMakeFiles/tests.dir/src/main.cpp.o
[ 66%] Linking CXX executable tests
Undefined symbols for architecture arm64:
  "__Z14print_vector1DISt6vectorIiSaIiEEEvT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE", referenced from:
      _main in main.cpp.o
  "__Z14print_vector2DISt6vectorIS0_IdSaIdEESaIS2_EEEvT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE", referenced from:
      _main in main.cpp.o
ld: symbol(s) not found for architecture arm64
collect2: error: ld returned 1 exit status
make[2]: *** [tests] Error 1
make[1]: *** [CMakeFiles/tests.dir/all] Error 2
make: *** [all] Error 2

I believe this is due to an incorrect way of including the header files in the project. Could someone give me a hint as to what is the right way?

Aucun commentaire:

Enregistrer un commentaire