CMake链接器无法识别头文件。

3
我是一名Linux编程的初学者,以下是我的问题。 我的项目是在Linux环境下使用C++编写的OpenCV项目。为了编译,我使用CMake来构建一个Makefile并运行。为了更清晰地说明,我也是新手在使用CMake方面。
首先,我有一个main.cpp文件,它启动了所有内容:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <cstdio>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <map>
#include <vector>
#include <cmath>
#include <dirent.h>
#include <algorithm>
#include <string.h>

using namespace std;

#include "constants.h"
#include "readData.cpp"
#include "features.cpp"
#include "featuresRGBD.cpp"

bool USE_HOG = true;

// print error message
void errorMsg(string message) {
    cout << "ERROR! " << message << endl;
    exit(1);
}

我们可以看到,我已经包含了一些预定义的文件,如:constants.h、readData.cpp、features.cpp和featuresRGBD.cpp。

在constaints.cpp中,我设置了一些常量变量:

const int SLEEP_TIME = 0;

const int JOINT_NUM = 11;
const int JOINT_DATA_ORI_NUM = 9;
const int JOINT_DATA_POS_NUM = 3;
const int JOINT_DATA_NUM = (JOINT_DATA_ORI_NUM+JOINT_DATA_POS_NUM);
const int JOINT_DATA_TYPE_NUM = 2; // two types : orientation and xyz position

const int TORSO_JOINT_NUM = 2;
const int HEAD_JOINT_NUM = 0;

const int POS_JOINT_NUM = 4;
const int POS_JOINT_DATA_NUM = 3;

const int POS_LEFT_HAND_NUM = 0;
const int POS_RIGHT_HAND_NUM = 1;
const int POS_LEFT_FOOT_NUM = 2;
const int POS_RIGHT_FOOT_NUM = 3;

const int X_RES = 320;
const int Y_RES = 240;
const int RGBD_data = 4;

// 30 fps
const int frameStoreNum = 66;
const int compareFrame[] = {0, -5, -9, -14, -20, -27, -35, -44, -54, -65};
const int compareFrameNum = sizeof(compareFrame)/sizeof(compareFrame[0]);

在readData.cpp中,我使用constants.cpp中的一些常量实现了我的方法。
bool READ_FROM_PNG = true;

class readData {
private:

    int currentFrameNum;
    int currentFrameNum_RGBD;
    int lastFrame;

    string dataLocation;
    string dataLocation_mirrored;
    string fileName;
    string fileName_skeleton;
    string fileName_RGBD;
    string curActivity;
    map<string, string> data_act_map;
    ifstream* file;
    ifstream* file_RGBD;

    bool mirrored;

    // print error message
    void errorMsg(string message, bool exitProgram) {
        cout << "ERROR! " << message << endl;
        printf("\tcurrentFrameNum = %d\n", currentFrameNum);
        printf("\tcurrentFrameNum_RGBD = %d\n", currentFrameNum_RGBD);

        if (exitProgram) {
            exit(1);
        }
    }    

    void errorMsg(string message) {
        errorMsg(message, true);
    }



    bool parseChk(bool chk, bool skeleton) {
        if (!chk) {
            if (skeleton) {
                errorMsg("parsing error. (skeleton)", true); 
            } else {
                errorMsg("parsing error. (RGBD) - IGNORE THIS ERROR!! (all random dataset will hit this error)", false);
            }
            return false;
        }
        return true;
    }

    // read skeleton data file
    void prepareSkeletonData() {
        curActivity = data_act_map[fileName];

        if (!mirrored) {
            fileName_skeleton = dataLocation + fileName + ".txt";
        } else {
            fileName_skeleton = dataLocation_mirrored + fileName + ".txt";
        }

        printf("\tOpening \"%s\" (%s)\n", (char*)fileName_skeleton.c_str(), (char*)curActivity.c_str());
        file = new ifstream((char*)fileName_skeleton.c_str(), ifstream::in);
        currentFrameNum = -99;
    }

    void closeSkeletonData() {
        file->close();
        printf("\tskeleton file closed\n");
    }

    // return true if data retrieving was successful
    bool readNextLine_skeleton(double **data, double **pos_data, int **data_CONF, int *data_pos_CONF) {
        string line;        
        bool file_ended = true;

        if (getline(*file,line)) {
            file_ended=false;
            stringstream lineStream(line);
            string element;

            int jointCount=0;  
            int joint_dataCount = 0;

            int pos_jointCount = 0;      
            int pos_joint_dataCount = 0;

            parseChk(getline(lineStream, element, ','), true);
            currentFrameNum = atoi((char*)element.c_str());

            if (element.compare("END") == 0) {
                file_ended = true;
                return false;
            }

            while (getline(lineStream, element, ',')) {
                double e = strtod((char*)element.c_str(), NULL);

                if (jointCount < JOINT_NUM) {
                    data[jointCount][joint_dataCount] = e;
                    joint_dataCount++;

                    if (joint_dataCount == JOINT_DATA_ORI_NUM) {
                        parseChk(getline(lineStream, element, ','), true); // ori conf value
                        data_CONF[jointCount][0] = atoi((char*)element.c_str());
                    } else if (joint_dataCount >= JOINT_DATA_NUM) {
                        parseChk(getline(lineStream, element, ','), true); // pos conf value
                        data_CONF[jointCount][1] = atoi((char*)element.c_str());
                        jointCount++;
                        joint_dataCount = 0;
                    }

                } else {
                    // pos only joints
                    if (pos_jointCount >= POS_JOINT_NUM) {
                        errorMsg("PARSING ERROR!!!!!");
                    }
                    pos_data[pos_jointCount][pos_joint_dataCount] = e;
                    pos_joint_dataCount++;
                    if (pos_joint_dataCount >= POS_JOINT_DATA_NUM) {
                        parseChk(getline(lineStream, element, ','), true); // pos conf value
                        data_pos_CONF[pos_jointCount] = atoi((char*)element.c_str());

                        pos_jointCount++;
                        pos_joint_dataCount = 0;
                    }
                }
            }

            // check if there is more data in current frame..
            if (getline(lineStream, element,',')) {
                errorMsg("more data exist in skeleton data ..\n");
            }

        } 

        if (currentFrameNum == -99) {
            errorMsg("file does not exist or empty!!");
        }

        return !file_ended;
    }

    // read RGBD data file
    void prepareRGBDData() {
        fileName_RGBD = dataLocation + fileName + "_rgbd.txt";
        printf("\tOpening \"%s\" (%s)\n", (char*)fileName_RGBD.c_str(), (char*)curActivity.c_str());
        file_RGBD = new ifstream((char*)fileName_RGBD.c_str(), ifstream::in);
        currentFrameNum = -99;
    }

    void closeRGBDData() {
        file_RGBD->close();
        printf("\tRGBD file closed\n");
    }

    // return true if data retrieving was successful
    bool readNextPNG(int ***data) {
        stringstream ss;
        ss << currentFrameNum;
        fileName_RGBD = dataLocation + fileName + "/RGB_" + ss.str() +".png";
        string fileName_Depth = dataLocation + fileName + "/Depth_" + ss.str() +".png";
        if (currentFrameNum == 1) {
            printf("\tOpening \"%s\" and so forth..\n", 
                    (char*)fileName_RGBD.c_str());
            printf("\tOpening \"%s\" and so forth..\n", 
                    (char*)fileName_Depth.c_str());
        }

        // Load an image from file
        cv::Mat rgbImage = cv::imread((char*)fileName_RGBD.c_str(),1);
        cv::Mat colorArr[3];
        cv::split(rgbImage, colorArr);

        cv::Mat depthImage = cv::imread((char*)fileName_Depth.c_str(),-1);

        if (rgbImage.data == NULL) {
            printf("ERROR! Unable to open file %s.\n", (char*)fileName_RGBD.c_str());
            exit(1);
        }
        if (depthImage.data == NULL) {
            printf("ERROR! Unable to open file %s.\n", (char*)fileName_Depth.c_str());
            exit(1);
        }

        for (int y=0; y<Y_RES; y++){ 
            // opencv uses BGR order
            uchar* Bptr = colorArr[0].ptr<uchar>(y); 
            uchar* Gptr = colorArr[1].ptr<uchar>(y); 
            uchar* Rptr = colorArr[2].ptr<uchar>(y); 
            ushort* IRptr = depthImage.ptr<ushort>(y); 
            for(int x=0;x<X_RES; x++){
                // our data is stored in RGB order
                data[x][y][0] = Rptr[x]; 
                data[x][y][1] = Gptr[x]; 
                data[x][y][2] = Bptr[x]; 
                data[x][y][3] = IRptr[x];
            } 
        } 

        return true;
    }

    // return true if data retrieving was successful
    bool readNextLine_RGBD(int ***IMAGE) {
        string line;        
        char* line_c;
        bool file_ended = true;

        if (getline(*file_RGBD,line)) {
            file_ended = false;

            line_c = (char*)line.c_str();
            char* element = strtok(line_c, ",");
            if (element == NULL || strcmp(element,"END") == 0) {
                file_ended = true;
                return false;
            }
            currentFrameNum_RGBD = atoi(element);
            if (currentFrameNum != currentFrameNum_RGBD) {
                printf("skeleton: %d rgbd: %d\n", currentFrameNum, currentFrameNum_RGBD);
                errorMsg("FRAME NUMBER BETWEEN SKELETON AND RGBD DOES NOT MATCH!!!!!!!!! (READING RGBD)");
            }

            for (int y=0;y<Y_RES;y++) {
                for (int x=0;x<X_RES;x++) {   
                    for (int d = 0; d<RGBD_data; d++) {     

                        element = strtok(NULL, ",");  // passing NULL keeps tokenizing previous call
                        if (element == NULL) {
                            file_ended = true;
                            return false;
                        }
                        int e = atoi(element);

                        if (!mirrored) {
                            IMAGE[x][y][d] = e;
                        } else {
                            IMAGE[x][(Y_RES-1)-y][d] = e; 
                        }
                    }
                }
            }            

            // check if there is more data in current frame..
            element = strtok(NULL, ",");  
            if (element != NULL) {
                printf("line_c = %s\n", line_c);
                errorMsg("more data exist in RGBD data ..\n");

            }

        } 

        return !file_ended;
    }

public:



    // return true if data retrieving was successful
    bool readNextFrame(double **data, double **pos_data, int **data_CONF, int *data_pos_CONF, int ***IMAGE) {
        if (currentFrameNum % 100 == 0) {
            printf("\t\t(progress..) frame num = %d\n", currentFrameNum);
        }
        bool status = readNextLine_skeleton(data,pos_data, data_CONF, data_pos_CONF);
        if (!status) {
            printf("\t\ttotal number of frames = %d\n", lastFrame);
            return false;
        }

        bool status_RGBD;
        if (!READ_FROM_PNG) {
            status_RGBD = readNextLine_RGBD(IMAGE);
        } else {
            status_RGBD = readNextPNG(IMAGE);    
        }
        if (status_RGBD) {
            lastFrame = currentFrameNum;
        } else {
            printf("\t\ttotal number of frames = %d\n", lastFrame);
        }
        return status_RGBD;
    }

    readData(string dataLoc, string fileN, map<string, string> d_a_map, int i, bool mirrored, string dataLoc_mirrored) {
        if (!mirrored) {
            printf("%d. ", i);    
        } else {
            printf("%d(M). ", i);
        }
        dataLocation = dataLoc;
        dataLocation_mirrored = dataLoc_mirrored;
        fileName = fileN;
        data_act_map = d_a_map;
        this->mirrored = mirrored;

        prepareSkeletonData();
        if (!READ_FROM_PNG) {
            prepareRGBDData();
        }
    }

    readData() {

    }

    ~readData(){
        closeSkeletonData();
        if (!READ_FROM_PNG) {
            closeRGBDData();
        }
        printf("\n");
    }

};

接着处理其他文件时,我也使用了一些预定义常量。然后,我编写了CMakeLists.txt以构建MakeFiles,就像这样:

cmake_minimum_required(VERSION 2.8)
project( FeatureExtractor )
find_package( OpenCV REQUIRED )
add_executable( FeatureExtractor main.cpp readData.cpp features.cpp featuresRGBD.cpp HOG.cpp HOGFeaturesOfBlock.cpp)
target_link_libraries( FeatureExtractor ${OpenCV_LIBS} )

我在某处看到过一句话,称"CMake可以自动处理依赖关系,因此无需列出头文件",所以我没有在配置的CMakeLists.txt中提到头文件(constaint.h)。

然后,当我运行命令组合并构建Makefile时,遇到了以下错误。

make
Scanning dependencies of target FeatureExtractor
[ 16%] Building CXX object CMakeFiles/FeatureExtractor.dir/main.cpp.o
[ 33%] Building CXX object CMakeFiles/FeatureExtractor.dir/readData.cpp.o
/home/minhthanh/Downloads/Test/readData.cpp:11:5: error: ‘string’ does not name a type
/home/minhthanh/Downloads/Test/readData.cpp:12:5: error: ‘string’ does not name a type
/home/minhthanh/Downloads/Test/readData.cpp:13:5: error: ‘string’ does not name a type
/home/minhthanh/Downloads/Test/readData.cpp:14:5: error: ‘string’ does not name a type
/home/minhthanh/Downloads/Test/readData.cpp:15:5: error: ‘string’ does not name a type
/home/minhthanh/Downloads/Test/readData.cpp:16:5: error: ‘string’ does not name a type
/home/minhthanh/Downloads/Test/readData.cpp:17:5: error: ‘map’ does not name a type
/home/minhthanh/Downloads/Test/readData.cpp:18:5: error: ‘ifstream’ does not name a type
/home/minhthanh/Downloads/Test/readData.cpp:19:5: error: ‘ifstream’ does not name a type
/home/minhthanh/Downloads/Test/readData.cpp:24:19: error: ‘string’ has not been declared
/home/minhthanh/Downloads/Test/readData.cpp:34:19: error: ‘string’ has not been declared
/home/minhthanh/Downloads/Test/readData.cpp:287:21: error: expected ‘)’ before ‘dataLoc’
/home/minhthanh/Downloads/Test/readData.cpp:317:2: error: expected ‘}’ at end of input
/home/minhthanh/Downloads/Test/readData.cpp: In member function ‘void readData::errorMsg(int, bool)’:
/home/minhthanh/Downloads/Test/readData.cpp:25:9: error: ‘cout’ was not declared in this scope
/home/minhthanh/Downloads/Test/readData.cpp:25:41: error: ‘endl’ was not declared in this scope
/home/minhthanh/Downloads/Test/readData.cpp:26:59: error: ‘printf’ was not declared in this scope
/home/minhthanh/Downloads/Test/readData.cpp:30:19: error: ‘exit’ was not declared in this scope
/home/minhthanh/Downloads/Test/readData.cpp: In member function ‘bool readData::parseChk(bool, bool)’:
/home/minhthanh/Downloads/Test/readData.cpp:43:59: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]
/home/minhthanh/Downloads/Test/readData.cpp:24:10: error:   initializing argument 1 of ‘void readData::errorMsg(int, bool)’ [-fpermissive]
/home/minhthanh/Downloads/Test/readData.cpp:45:119: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]
/home/minhthanh/Downloads/Test/readData.cpp:24:10: error:   initializing argument 1 of ‘void readData::errorMsg(int, bool)’ [-fpermissive]
/home/minhthanh/Downloads/Test/readData.cpp: In member function ‘void readData::prepareSkeletonData()’:
/home/minhthanh/Downloads/Test/readData.cpp:54:9: error: ‘curActivity’ was not declared in this scope
/home/minhthanh/Downloads/Test/readData.cpp:54:23: error: ‘data_act_map’ was not declared in this scope

尽管是一个很长的列表,但我猜问题在于我在main.cpp中包含的某些库和文件未被下面的文件(readData.cpp、features.cpp等)识别。如何进行配置或修改才能让我在下面包含的这些预定义文件和库被识别呢?

1
很高兴你提供了这么多信息,但是以后请考虑将你的问题隔离开来。这里有很多不必要的代码,没有必要去解决你的问题。 - Litty
1
是的。这是我第一次在StackOverflow上发布问题,我感到非常沮丧。谢谢你的建议,我会认真考虑下一次发布。 :) - Thành Võ Minh
1个回答

3
问题在于CMake单独编译了readData.cpp文件,但是其中没有包含和using namespace std;,因此无法编译通过。
如果你在main.cpp中包含了readData.cpp、features.cpp、featuresRGBD.cpp等文件(如你所见已经编译通过),那么你就不需要在CMake中为它们设置单独的编译,也就是从CMake的add_executable(...)行中去除它们。
但通常情况下,我们会采用另一种方式,即将每个*.cpp文件分别编译,而不是在main.cpp中包含它们,并且在每个文件中只包含它们所需的内容。

1
是啊。我无法形容我的感激之情。这个问题花了我将近一周的时间才解决。再次感谢你。我希望我能投多张票 :) - Thành Võ Minh
@ThànhVõMinh:别忘了实际接受这个答案,这样作者才能得到应有的声望积分。请参阅 meta.stackexchange.com/a/5235/160242 。祝大家好运。 - shellter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接