C++ C+的制作与编译+;包含多个文件的项目

C++ C+的制作与编译+;包含多个文件的项目,c++,g++,C++,G++,我是C/C++新手,我已经知道了基础知识,现在我开始学习更高级的概念 目前我正在用C++开发一个工程,它是一个很大的项目,所以构造我的项目会更好。 据我所见,一个好的结构至少依赖于文件夹:/src和/include。所有.cpp文件应放在/src文件夹中,而.hpp文件应放在/include文件夹中。这里出现了第一个疑问:如何包含不在同一目录或标准目录中的标题?搜索之后,我得出结论,最好的方法是将选项-I../include传递给编译器 我有三个源文件:main.cpp、GraphData.cp

我是C/C++新手,我已经知道了基础知识,现在我开始学习更高级的概念

目前我正在用C++开发一个工程,它是一个很大的项目,所以构造我的项目会更好。 据我所见,一个好的结构至少依赖于文件夹:
/src
/include
。所有.cpp文件应放在
/src
文件夹中,而.hpp文件应放在
/include
文件夹中。这里出现了第一个疑问:如何包含不在同一目录或标准目录中的标题?搜索之后,我得出结论,最好的方法是将选项
-I../include
传递给编译器

我有三个源文件:main.cpp、GraphData.cpp和RandomGraphGenerator.cpp。我已经读到,最好的做法是为每个文件都有一个头,将声明和定义分开。现在我也有两个头,但我不知道如何编译所有这些

我正在集中精力使GraphData.cpp正确链接到main.cpp,我评论了所有需要RandomGraphGenerator.cpp的内容。这是我的主文件:

// main.cpp
#include <iostream>
#include <string>
#include <Snap.h>
#include <GraphData.hpp>

int main() {
    std::string file_path;
    char path[1024];
    DataPoint **data_set;
    int motif_size, num_null_models;

    std::cin >> file_path;
    std::cin >> motif_size;
    std::cin >> num_null_models;

    data_set = new DataPoint*[num_null_models];

    strncpy(path, file_path.c_str(), sizeof(path));
    path[sizeof(path) - 1] = 0;

    //read input
    PNGraph G = TSnap::LoadEdgeList<PNGraph>(path, 0, 1);

    //enumerate and classify k-subgraphs in G
    GD::extractData(&G, motif_size, data_set[0]);

    //generate random graphs and enumerate and calssify k-subgraphs on them
    for(int i=1; i<=num_null_models; i++) {
        //GM::randomize(&G);
        GD::extractData(&G, motif_size, data_set[i]);
    }

    //detect motifs
    GD::discoverMotifs(data_set);

    return 0;
}
但它给了我一个未定义引用的错误:

main.cpp:(.text+0x179): undefined reference to `GD::extractData(TPt<TNGraph>*, int, DataPoint*)'
main.cpp:(.text+0x1b9): undefined reference to `GD::extractData(TPt<TNGraph>*, int, DataPoint*)'
main.cpp:(.text+0x1dd): undefined reference to `GD::discoverMotifs(DataPoint**)'
collect2: error: ld returned 1 exit status
main.cpp:(.text+0x179):对“GD::extractData(TPt*,int,DataPoint*)”的未定义引用
main.cpp:(.text+0x1b9):对“GD::extractData(TPt*,int,DataPoint*)”的未定义引用
main.cpp:(.text+0x1dd):对“GD::discovermotions(DataPoint**)”的未定义引用
collect2:错误:ld返回了1个退出状态

我对它有点迷茫,我遗漏了什么?

[注意:这不是问题的答案,只是一个关于如何逐个编译多个文件的解释]

您可以单独编译源文件,但必须告诉
g++
创建对象文件,然后将其链接在一起

大概是这样的:

$ g++ -Wall -g -c -I../include -I/usr/include/Snap-2.3/snap-core -I/usr/include/Snap-2.3/glib-core main.cpp
$ g++ -Wall -g -c -I../include -I/usr/include/Snap-2.3/snap-core -I/usr/include/Snap-2.3/glib-core GraphData.cpp
$ g++ -g  main.o GraphData.o /usr/include/Snap-2.3/snap-core/Snap.o -o main
选项
-Wall
告诉
g++
要启用更多警告,这是很好的,因为警告是您可能做错了事情的迹象(例如导致错误)。
-g
选项告诉
g++
生成调试信息,当您需要在调试器中运行程序时,在开发过程中始终可以获得这些信息。最后,
-c
选项告诉
g++
生成一个目标文件而不是一个可执行程序

然后有一个单独的命令将对象文件链接在一起,形成最终的可执行文件


如果你得到的文件不止两个,这一切都会成为一种后遗症,然后你应该了解哪一个程序可以为你自动完成大部分工作。例如,它将检查文件上的时间戳,以确保您不编译未修改的文件。

g++默认情况下在编译完所有输入文件后立即调用链接器(ld)。生成二进制可执行文件的方法有很多,但最常见的两种是:

  • 在单个
    g++
    命令中包含所有源文件。您需要将
    GraphData.cpp
    main.cpp
    添加到对
    g++
    的相同调用中。 此方法确保链接器可以访问所有符号以创建可执行文件
  • 将每个文件分别编译成一个对象文件,并在单独的步骤中链接它们(这在大型软件项目中更常见)。 为此,请将每个cpp文件的
    -c
    开关传递到
    g++
    ,然后再次调用g++并传递
    .o
    文件,而不是
    .cpp
    文件
  • 无论哪种方式,在某个时刻,您必须一次性将所有符号提供给链接器,以便它可以创建可执行文件


    正如Joachim所解释的,除了几个文件之外的任何东西都会成为一种巨大的痛苦,在这一点上,学习构建系统是非常有利可图的。他提到了制作,但我也会考虑研究哪种语法更简单,而且是跨平台的。它甚至可以自动为您生成
    makefile

    您只是在编译main.cpp文件。您需要编译所有的cpp文件。@JohnDrouhard我试过了,试图按原样编译它们会产生奇怪的错误,这似乎与它们缺少主函数有关。我添加了一个空的主函数,然后进行编译,但原始问题仍然存在。您尝试在一个命令中编译它们?在
    main.cpp
    @JohnDrouhard之后添加
    GraphData.cpp
    ,谢谢!我认为我必须先编译GraphData,然后再编译main.cpp。对不起,这篇愚蠢的帖子。让你的评论成为一个答案,这样我就可以接受。不是一篇愚蠢的帖子。Dumb post会遗漏所有代码、编译器和平台以及错误消息。实际上,这篇文章写得不错。
    g++ -o main main.cpp /usr/include/Snap-2.3/snap-core/Snap.o -I../include -I/usr/include/Snap-2.3/snap-core -I/usr/include/Snap-2.3/glib-core
    
    main.cpp:(.text+0x179): undefined reference to `GD::extractData(TPt<TNGraph>*, int, DataPoint*)'
    main.cpp:(.text+0x1b9): undefined reference to `GD::extractData(TPt<TNGraph>*, int, DataPoint*)'
    main.cpp:(.text+0x1dd): undefined reference to `GD::discoverMotifs(DataPoint**)'
    collect2: error: ld returned 1 exit status
    
    $ g++ -Wall -g -c -I../include -I/usr/include/Snap-2.3/snap-core -I/usr/include/Snap-2.3/glib-core main.cpp
    $ g++ -Wall -g -c -I../include -I/usr/include/Snap-2.3/snap-core -I/usr/include/Snap-2.3/glib-core GraphData.cpp
    $ g++ -g  main.o GraphData.o /usr/include/Snap-2.3/snap-core/Snap.o -o main