C++;,";老式的;方式 我在学校学习C++来创建小命令行程序。

C++;,";老式的;方式 我在学校学习C++来创建小命令行程序。,c++,makefile,build-process,toolchain,C++,Makefile,Build Process,Toolchain,然而,我只使用IDE构建了我的项目,包括VS08和QtCreator 我理解构建项目背后的过程:将源代码编译为目标代码,然后将它们链接到平台特定的可执行文件(.exe,.app,等等)。我还知道大多数项目也使用make来简化编译和链接多个源文件和头文件的过程 问题是,尽管IDE在幕后完成了所有这些,使生活变得非常简单,但我真的不知道到底发生了什么,我觉得我需要习惯于以“老式的方式”构建项目:从命令行开始,明确地使用工具链 我知道什么是Makefiles,但不知道如何编写它们。 我知道gcc的功能

然而,我只使用IDE构建了我的项目,包括VS08和QtCreator

我理解构建项目背后的过程:将源代码编译为目标代码,然后将它们链接到平台特定的可执行文件(
.exe
.app
,等等)。我还知道大多数项目也使用
make
来简化编译和链接多个源文件和头文件的过程

问题是,尽管IDE在幕后完成了所有这些,使生活变得非常简单,但我真的不知道到底发生了什么,我觉得我需要习惯于以“老式的方式”构建项目:从命令行开始,明确地使用工具链

我知道什么是
Makefile
s,但不知道如何编写它们。
我知道gcc的功能,但不知道如何使用它。
我知道链接器做什么,但不知道如何使用它

我所寻求的,是一个解释,或者是链接到一个教程,解释了C++项目的工作流程,从第一次编写代码到运行生成的可执行文件。 我很想知道C++的构造、构造和构造的原因。 (如果有什么不同的话,我运行的是MacOSX,GCC4.0.1和Make3.81)


谢谢

编译器接受一个cpp并转换成一个包含本机代码和有关该本机代码的一些信息的对象文件

链接器获取目标文件,并使用目标文件中的额外信息布局可执行文件。。。。它会找到对相同事物的所有引用并将它们链接起来,并使和image对操作系统了解如何将所有代码加载到内存中非常有用

查看对象文件格式以更好地了解编译器生成的内容

(不同的编译器使用不同的格式)

也请检查(对于gcc)


对于在命令行键入的内容,一个简单的示例通常有助于显示基本过程,因此:

示例GCC使用编译C++文件:

$ g++ -c file1.cpp                 # compile object files
[...]
$ g++ -c file2.cpp
[...]
$ g++ -o program file1.o file2.o   # link program
[...]
$ ./program                        # run program
要使用
make
进行此生成,可以使用以下Makefile:

# main target, with dependencies, followed by build command (indented with <tab>)
program: file1.o file2.o
    g++ -o program file1.o file2.o

# rules for object files, with dependencies and build commands
file1.o: file1.cpp file1.h
    g++ -c file1.cpp

file2.o: file2.cpp file2.h file1.h
    g++ -c file2.cpp
有关所有详细信息,请参见和

我知道makefile是什么,但不知道如何编写它们

make语法很糟糕,但语法也不错。主要语法是:

<target> : <dependency> <dependency> <dep...>
<tab>    <command>
<tab>    <command>
您还可以编写自己的shell脚本(下面是my~/bin/c++简化版),以合并$CXXFLAGS,这样您就不会忘记:

#!/bin/sh
g++ $CXXFLAGS "$@"
您还可以包括任何其他选项。现在,您可以在.BasHC或类似的环境中设置环境变量($cxFLAGS,C++变量的标准变量),或者在特定的会话中重新定义它,用于不使用MaFIX文件(这也使得它也很好)。 还可以使用
-v
标志查看有关g++功能的详细信息,包括

我知道链接器做什么,但不知道如何使用它

链接器是获取对象文件并链接它们的东西,我相信您知道,但是
g++-v
将向您显示它使用的确切命令。比较<代码> Gcc-V文件.CPP < /C>(GCC可以与C++文件一起工作)和<代码> G++-V文件.CPP < /C> >以查看链接器命令中的差异,这些链接命令常常导致第一个失败。默认情况下,“Make”还会在运行命令时显示这些命令


最好不要直接使用链接器,因为使用gcc或g++并在需要时为它们提供特定的链接器选项要简单得多。

仅此而已,完整的gcc文档可以在此处找到:

编译 假设您想编写一个简单的“hello world”应用程序。您有3个文件,
hello.cpp
hello writer.cpp
hello writer.h
,内容如下:

// hello-writer.h
void WriteHello(void);

// hello-writer.cpp
#include "hello-writer.h"
#include <stdio>
void WriteHello(void){
    std::cout<<"Hello World"<<std::endl;
}

// hello.cpp
#include "hello-writer.h"
int main(int argc, char ** argv){
    WriteHello();
}
-c
标志暂时跳过链接。要将所有模块链接在一起,需要运行

g++ hello.o hello-writer.o -o hello
正在创建程序
hello
。如果需要链接任何外部库,请将它们添加到此行,例如数学库的
-lm
。实际的库文件看起来像
libm.a
libm。因此
,在添加链接器标志时忽略文件名的后缀和“lib”部分

生成文件 要使构建过程自动化,您需要使用一个makefile,它由一系列规则组成,列出要创建的对象和创建它所需的文件。例如,
hello.o
依赖于
hello.cpp
hello writer.h
,其规则是

hello.o:hello.cpp hello-writer.h
     g++ -c hello.cpp -o hello.o # This line must begin with a tab.
如果你想阅读make手册,它会告诉你如何使用变量和自动规则来简化事情。你应该会写

hello.o:hello.cpp hello-writer.h
规则将自动创建。hello示例的完整makefile是

all:hello
hello:hello.o hello-writer.o
    g++ hello.o hello-writer.o -o hello
hello.o:hello.cpp hello-writer.h
    g++ -c hello.cpp -o hello.o
hello-writer.o:hello-writer.cpp hello-writer.h
    g++ -c hello-writer.cpp -o hello-writer.o
请记住,缩进行必须以制表符开头。并非所有规则都需要实际的文件,
all
目标只是说create
hello
。这通常是makefile中的第一条规则,第一条规则在运行
make
时自动创建

完成所有这些设置后,您应该能够转到命令行并运行

$ make
$ ./hello
Hello World
更高级的Makefile东西 您还可以在makefile中定义一些有用的变量,包括

  • CX:C++编译器
  • CXXFLAGS: 要传递到的其他标志 编译器(例如包括目录) 带-I)
  • LDFLAGS:要添加的其他标志 传递给链接器
  • 图书馆 连结
  • CC:c编译器(也用于 链接)
  • CPPFLAGS:预处理器标志
使用
=
定义变量,使用
+=
添加到变量

将.cpp文件转换为.o文件的默认规则为

$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@
其中,
$^
是所有先决条件。此规则将使用模式
hello:hello.o hello writer.o
运行。请注意,如果您不想重写此规则并且
all:hello
hello:hello.o hello-writer.o
    g++ hello.o hello-writer.o -o hello
hello.o:hello.cpp hello-writer.h
    g++ -c hello.cpp -o hello.o
hello-writer.o:hello-writer.cpp hello-writer.h
    g++ -c hello-writer.cpp -o hello-writer.o
$ make
$ ./hello
Hello World
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< -o $@
$(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS)
LDLIBS+=-lstdc++
LDFLAGS=-lstdc++
all:hello
hello:hello.o hello-writer.o
// Makefile
CC=gcc
CXX=g++
CXXFLAGS+=-Wall -Wextra -Werror
CXXFLAGS+=-Ipath/to/headers
LDLIBS+=-lstdc++ # You could instead use CC = $(CXX) for the same effect 
                 # (watch out for c code though!)

all:hello                                   # default target
hello:hello.o hello-world.o                 # linker
hello.o:hello.cpp hello-world.h             # compile a module
hello-world.o:hello-world.cpp hello-world.h # compile another module
    $(CXX) $(CXXFLAGS) -c $< -o $@          # command to run (same as the default rule)
                                            # expands to g++ -Wall ... -c hello-world.cpp -o hello-world.o