用多个文件制作和编译C 项目
Making and compiling C++ projects with multiple files
我是C/C 的新手,我已经知道基础知识,现在开始学习更多高级概念。
目前,我正在使用C 开发一个项目,这是一个很大的项目,因此结构我的项目会更好。
从我已经看到的内容来看,一个好的结构至少依赖于文件夹:/src
和/include
。所有.CPP文件都应在/src
文件夹中,并在/include
中的.HPP中使用。首先出现了第一个疑问:如何包括一个不在同一目录或标准目录中的标头?在搜索它之后,我得出的结论是,最好的方法是将选项-I../include
传递给编译器。
我有三个源文件:main.cpp,graphdata.cpp和randomgraphgenerator.cpp。我读到,为每个文件中的每个文件都有一个标题,将声明与定义分开是最好的实践。现在我也有两个标题,但是我没有得到如何编译所有这些。
我正在专注于将graphdata.cpp正确链接到main.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;
}
我的GraphData标头:
#ifndef GRAPHDATA_HPP_INCLUDED
#define GRAPHDATA_HPP_INCLUDED
#include <Snap.h>
struct DataPoint;
namespace GD {
void extractData(PNGraph*, int, DataPoint*);
DataPoint* discoverMotifs(DataPoint**);
}
#endif // GRAPHDATA_HPP_INCLUDED
和我的GraphData文件:
#include <GraphData.hpp>
struct DataPoint {
int label;
int frequency = 0;
};
void GD::extractData(PNGraph* G, int k, DataPoint* data_array) {
//stuff
}
DataPoint* GD::discoverMotifs(DataPoint** data_set) {
//dummy code
DataPoint* dp;
dp = new DataPoint[2];
dp[0].label = 10;
dp[1].label = 99;
return dp;
}
我试图在Ubuntu 14.10下使用GCC 4.9.2进行编译,使用:
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 默认情况下,一旦完成了所有输入文件,就会立即调用链接器(LD)。生产二进制可执行文件的方法有很多,但是最常见的两个方法是:
- 将所有源文件包括在一个
g++
命令中。您需要将GraphData.cpp
和main.cpp
添加到g++
的同一调用中。此方法可确保链接器可以访问所有符号以创建可执行文件。 - 将每个文件分别编译到对象文件中,然后在单独的步骤中链接它们(对于大型软件项目而言,这更常见)。为此,请将
-c
开关传递到每个CPP文件的g++
,然后再次致电G 并传递.o
文件而不是.cpp
文件。
无论哪种方式,在某个时候,您都必须一次将所有符号提供给链接器,以创建可执行文件。
正如约阿希姆(Joachim)所解释的那样,几个文件以外的任何事物都会变得巨大的痛苦,此时学习构建系统可能是非常有利可图的。他提到了制造,但我也考虑研究具有更简单的语法并且是跨平台的Cmake。它甚至可以自动生成Makefiles
。
[注意:这不是问题的答案,这只是关于如何一个一个一个一个汇编多个文件的解释]
you can 分别编译源文件,但是您必须告诉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++
启用更多警告,这是很好的,因为警告是您可能做错事的迹象(例如引起 undfined行为)。-g
选项告诉g++
生成调试信息,如果您需要在调试器中运行该程序,则在开发过程中始终可以使用。最后,-c
选项是告诉g++
生成对象文件而不是可执行程序的方法。
然后,您有一个单独的命令,将对象文件链接在一起以形成最终可执行文件。
如果您收到了多个文件,那么这一切都会在背面痛苦,然后您应该了解make
,这是一个可以为您自动化的程序。例如,它将检查文件上的时间戳记,以确保您不编译未修改的文件。
- 当我尝试通过 mingw 使用 CMake 和 SFML 库编译项目时出错
- LD:尝试编译项目时找不到架构x86_64符号
- 如何在不需要LIBCD.lib的情况下在Visual Studio 6中编译C项目
- 如何使用 Makefile 使用 VTK 库编译项目?
- UE4无法使用vs2017编译C++项目
- 无法让 CMAKE 编译项目
- 了解如何编译C++项目
- [UE4错误]无法编译项目.你想在Visual Studio中打开它吗?
- 使用 -O1 优化标志编译项目时共享库崩溃
- 每次都构建(make)lib,只有在lib较新时才重新编译项目
- 如何在 g++ 上使用 opencv 编译项目 c++
- 尝试使用 TMXlite 编译项目时LNK2019错误
- 编译项目时文件无效或损坏,包括 V8
- 为什么当我在Visual Studio中编译C++项目时会出现致命错误"LNK1104:无法打开文件'cryptlib.lib'?
- 在 netbeans 中编译项目中的单个文件
- 用cmake中的makefile编译项目
- 使用makefile编译C++项目时出现问题
- 用多个文件制作和编译C 项目
- 如何有条件地为 Eclipse 中的交叉编译项目包含两个不同名称的相同版本的库
- 如何编译项目后不运行exe文件