Linux环境使用g++编译C++方法总结

单个源文件生成可执行程序

下面是一个保存在文件 helloworld.cpp 中一个简单的 C++ 程序的代码:

/* helloworld.cpp */
#include <iostream>
int main(int argc,char *argv[])
{
  std::cout << "hello, world" << std::endl;
  return(0);
}

程序使用定义在头文件 iostream 中的 cout,向标准输出写入一个简单的字符串。该代码可用以下命令编译为可执行文件:

$ g++ helloworld.cpp

编译器 g++ 通过检查命令行中指定的文件的后缀名可识别其为 C++ 源代码文件。编译器默认的动作:编译源代码文件生成对象文件(object file),链接对象文件和 libstdc++ 库中的函数得到可执行程序。然后删除对象文件。由于命令行中未指定可执行程序的文件名,编译器采用默认的 a.out。程序可以这样来运行:

$ ./a.out
hello, world

更普遍的做法是通过 -o 选项指定可执行程序的文件名。下面的命令将产生名为 helloworld 的可执行文件:

$ g++ helloworld.cpp -o helloworld

在命令行中输入程序名可使之运行:

$ ./helloworld
hello, world

程序 g++ 是将 gcc 默认语言设为 C++ 的一个特殊的版本,链接时它自动使用 C++ 标准库而不用 C 标准库。通过遵循源码的命名规范并指定对应库的名字,用 gcc 来编译链接 C++ 程序是可行的,如下例所示:

$ gcc helloworld.cpp -lstdc++ -o helloworld

选项 -l (ell) 通过添加前缀 lib 和后缀 .a 将跟随它的名字变换为库的名字 libstdc++.a。而后它在标准库路径中查找该库。gcc 的编译过程和输出文件与 g++ 是完全相同的。

在大多数系统中,GCC 安装时会安装一名为 c++ 的程序。如果被安装,它和 g++ 是等同,如下例所示,用法也一致:

$ c++ helloworld.cpp -o helloworld

多个源文件生成可执行程序

如果多于一个的源码文件在 g++ 命令中指定,它们都将被编译并被链接成一个单一的可执行文件。下面是一个名为 speak.h 的头文件;它包含一个仅含有一个函数的类的定义:

/* speak.h */
#include <iostream>
class Speak
{
  public:
    void sayHello(const char *);
};

下面列出的是文件 speak.cpp 的内容:包含 sayHello() 函数的函数体:

/* speak.cpp */
#include "speak.h"
void Speak::sayHello(const char *str)
{
  std::cout << "Hello " << str << "\n";
}

文件 hellospeak.cpp 内是一个使用 Speak 类的程序:

/* hellospeak.cpp */
#include "speak.h"
int main(int argc,char *argv[])
{
  Speak speak;
  speak.sayHello("world");
  return(0);
}

下面这条命令将上述两个源码文件编译链接成一个单一的可执行程序:

$ g++ hellospeak.cpp speak.cpp -o hellospeak

PS:这里说一下为什么在命令中没有提到“speak.h“该文件(原因是:在“speak.cpp“中包含有”#include"speak.h"“这句代码,它的意思是搜索系统头文件目录之前将先在当前目录中搜索文件“speak.h“。而”speak.h“正在该目录中,不用再在命令中指定了)。

源文件生成对象文件

选项 -c 用来告诉编译器编译源代码但不要执行链接,输出结果为对象文件。文件默认名与源码文件名相同,只是将其后缀变为 .o。例如,下面的命令将编译源码文件 hellospeak.cpp 并生成对象文件 hellospeak.o:

$ g++ -c hellospeak.cpp

命令 g++ 也能识别 .o 文件并将其作为输入文件传递给链接器。下列命令将编译源码文件为对象文件并将其链接成单一的可执行程序:

$ g++ -c hellospeak.cpp
$ g++ -c speak.cpp
$ g++ hellospeak.o speak.o -o hellospeak

选项 -o 不仅仅能用来命名可执行文件。它也用来命名编译器输出的其他文件。例如:除了中间的对象文件有不同的名字外,下列命令生将生成和上面完全相同的可执行文件:

$ g++ -c hellospeak.cpp -o hspk1.o
$ g++ -c speak.cpp -o hspk2.o
$ g++ hspk1.o hspk2.o -o hellospeak

编译预处理

选项 -E 使 g++ 将源代码用编译预处理器处理后不再执行其他动作。下面的命令预处理源码文件 helloworld.cpp 并将结果显示在标准输出中:

$ g++ -E helloworld.cpp

本文前面所列出的 helloworld.cpp 的源代码,仅仅有六行,而且该程序除了显示一行文字外什么都不做,但是,预处理后的版本将超过 1200 行。这主要是因为头文件 iostream 被包含进来,而且它又包含了其他的头文件,除此之外,还有若干个处理输入和输出的类的定义。

预处理过的文件的 GCC 后缀为 .ii,它可以通过 -o 选项来生成,例如:

$ gcc -E helloworld.cpp -o helloworld.ii

生成汇编代码

选项 -S 指示编译器将程序编译成汇编语言,输出汇编语言代码而後结束。下面的命令将由 C++ 源码文件生成汇编语言文件 helloworld.s:

$ g++ -S helloworld.cpp

生成的汇编语言依赖于编译器的目标平台。

创建静态库

静态库是编译器生成的一系列对象文件的集合。链接一个程序时用库中的对象文件还是目录中的对象文件都是一样的。库中的成员包括普通函数,类定义,类的对象实例等等。静态库的另一个名字叫归档文件(archive),管理这种归档文件的工具叫 ar 。

在下面的例子中,我们先创建两个对象模块,然后用其生成静态库。

头文件 say.h 包含函数 sayHello() 的原型和类 Say 的定义:

/* say.h */
#include <iostream>
void sayhello(void);
class Say {
  private:
    char *string;
  public:
    Say(char *str)
    {
      string = str;
    }
    void sayThis(const char *str)
    {
      std::cout << str << " from a static library\n";
    }
    void sayString(void);
};

下面是文件 say.cpp 是我们要加入到静态库中的两个对象文件之一的源码。它包含 Say 类中 sayString() 函数的定义体;类 Say 的一个实例 librarysay 的声明也包含在内:

/* say.cpp */
#include "say.h"
void Say::sayString()
{
  std::cout << string << "\n";
}

Say librarysay("Library instance of Say");

源码文件 sayhello.cpp 是我们要加入到静态库中的第二个对象文件的源码。它包含函数 sayhello() 的定义:

/* sayhello.cpp */
#include "say.h"
void sayhello()
{
  std::cout << "hello from a static library\n";
}

下面的命令序列将源码文件编译成对象文件,命令 ar 将其存进库中:

$ g++ -c sayhello.cpp
$ g++ -c say.cpp
$ ar -r libsay.a sayhello.o say.o

程序 ar 配合参数 -r 创建一个新库 libsay.a 并将命令行中列出的对象文件插入。采用这种方法,如果库不存在的话,参数 -r 将创建一个新的库,而如果库存在的话,将用新的模块替换原来的模块。

下面是主程序 saymain.cpp,它调用库 libsay.a 中的代码:

/* saymain.cpp */
#include "say.h"
int main(int argc,char *argv[])
{
  extern Say librarysay;
  Say localsay = Say("Local instance of Say");
  sayhello();
  librarysay.sayThis("howdy");
  librarysay.sayString();
  localsay.sayString();
  return(0);
}

该程序可以下面的命令来编译和链接:

$ g++ saymain.cpp libsay.a -o saymain

程序运行时,产生以下输出:

hello from a static library
howdy from a static library
Library instance of Say
Local instance of Say

ps:如果一个文件夹下有多个cpp文件需要编译的话,除了采用makefile的方式之外,还可以使用“g++ *.cpp -o hello",“hello为编译生成的可执行文件的名字”,编译时要确保cpp文件和他们各自所引用的头文件在同一个目录下。

您可能感兴趣的文章:

  • 详解 linux c++的编译器g++的基本使用
  • linux下C/C++学生信息管理系统
  • 关于安装linux redhat后无法使用yum命令安装gcc-c++问题的解决过程
  • 在Linux下编译C或C++程序的教程
  • linux系统中c++写日志文件功能分享
  • Linux上搭建C/C++IDE开发环境
(0)

相关推荐

  • 关于安装linux redhat后无法使用yum命令安装gcc-c++问题的解决过程

    初入职场,给linux redhat安装环境的时候,遇到这么个问题 [root@localhost ~]# yum -y install gcc Loaded plugins: katello, product-id, security, subscription-manager Updating certificate-based repositories. Unable to read consumer identity Setting up Install Process No packa

  • Linux上搭建C/C++IDE开发环境

    文/张善友 Redhat linux上面没有提供Anjuta软件包,上面提供了一个Glade应用程序界面设计工具.Linux上面使用Anjuta和Glade以及Glademm软件包可以搭建一个linux下面进行C/C++软件开发的IDE环境,可以进行GTK+/Gnome的应用程序开发. 以前开发 Linux 程序时写出好的图形化用户界面比较难.在 GIMP 工具包 (GTK)诞生之后,这件事就变得比较容易了.当Damon Chaplin 写出 GLADE 这个用于在 GTK 环境下生成图形化用户

  • 详解 linux c++的编译器g++的基本使用

    linux c++的编译器g++基本使用 g++是 linux下c++的编译器,在执行编译工作的时候,总共需要4步 1.预处理,生成.i的文件 2.将预处理后的文件不转换成汇编语言,生成文件.s 3.有汇编变为目标代码(机器代码)生成.o的文件 4.连接目标代码,生成可执行程序 g++ 编译c++经常使用的参数: -c 只编译,不连接.例如: g++ -c helloworld.cpp 只生成helloworld.o不连接 -o 指定输出文件名.例如:g++ -c helloworld.cpp

  • 在Linux下编译C或C++程序的教程

    从开始学习C/C++我们都在是windows下,那么如何(怎样)在linux中编译C/C++代码?在linux终端下(命令行中)编译译C/C++代码? 在任何linux分支下编译C/C++代码,如 Ubuntu ,Red Hat, Fedora ,Debian 以及其他linux分支上,我们需要安装一下软件包: 1.GNU C and C++ compiler collection 2.Development tools 3.Development libraries 4.IDE or text

  • linux系统中c++写日志文件功能分享

    简化了glog,只保留了写日志文件的功能,只是改写了linux版本,win版本未改写,可以用LOG(INFO)<< 输出日志也可用LOG_IF(INFO,condition)<<输出日志也可直接调用日志类Logger::GetInstance().Error 等方式写日志初始化时调用 InitLogging(argv[0],INFO,"./log/test");第一个参数是路径,第二个参数是最低日志级别,第三个参数表示日志文件的前缀和文件夹 FileHelper

  • linux下C/C++学生信息管理系统

    一.简介 大学期间用vc++开发的简单的学生信息管理系统,主要有添加学生信息.删除学生信息.修改学生信息.查询学生信息.显示学生信息.综合统计(各课程平均成绩和合格率).总分排序和退出系统.设计: 二.详解 1.代码 (1)main.cpp #include<iostream> #include<fstream> #include<iomanip> //使用setw()函数 #include<windows.h> //使用system()函数 #includ

  • Linux环境使用g++编译C++方法总结

    单个源文件生成可执行程序 下面是一个保存在文件 helloworld.cpp 中一个简单的 C++ 程序的代码: /* helloworld.cpp */ #include <iostream> int main(int argc,char *argv[]) { std::cout << "hello, world" << std::endl; return(0); } 程序使用定义在头文件 iostream 中的 cout,向标准输出写入一个简单的

  • linux下使用g++编译cpp工程的方法

    C++编程中相关文件后缀 1.单个源文件生成可执行程序 下面是一个保存在文件 helloworld.cpp 中一个简单的 C++ 程序的代码: /* helloworld.cpp */ #include <iostream> int main(int argc,char *argv[]) { std::cout << "hello, world" << std::endl; return(0); } 程序使用定义在头文件 iostream 中的 co

  • Linux环境下的备份

    Linux系统管理员常常问的一个问题是:如何备份我的系统?对于windows系统来说,进行备份是很简单的工作(仅仅需要在菜单模式下点击鼠标就可以完成). Linux备份工作则要麻烦的多,若你不熟悉Linux系统文件和设备,情况则会变得更糟.该篇文章讨论了在Linux环境下保护数据的方法和相关的设备信息. 1.什么是备份? 最简单的讲,备份数据的过程就是拷贝重要的数据到其他的介质之上(通常是可移动的),以保证在原始数据丢失的情况下可以恢复数据.一次备份可能是简单的cp命令,将一个文件复制到其他目录

  • Linux下g++编译与使用静态库和动态库的方法

    在windows环境下,我们通常在IDE如VS的工程中开发C++项目,对于生成和使用静态库(*.lib)与动态库(*.dll)可能都已经比较熟悉,但是,在linux环境下,则是另一套模式,对应的静态库(*.a)与动态库(*.so)的生成与使用方式是不同的.刚开始可能会不适应,但是用多了应该会习惯这种使用,因为步骤上并没有VS下配置那么繁琐. 下面就分别总结下linux下生成并使用静态库与动态库的方法:(由于是C++项目,所以编译器用的g++,但是与gcc的使用是相通的) 首先是准备工作,把我们需

  • Linux配置C++11编译环境的方法

    配置yum源 此处我们使用163的yum源,配置如下 首先备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 下载对应版本repo文件, 放入/etc/yum.repos.d/(操作前请做好相应备份),以下为下载链接 https://mirrors.163.com/.help/CentOS6-Base-163.repo 运

  • Linux环境g++编译GDAL动态库操作方法

    一.编译步骤 解压下载的GDAL源程序,并在命令行中切换到解压目录. tar -xzvf gdal-2.1.3.tar.gz cd gdal-2.1.3 GDAL可通过configure来实现一些自定义配置,可通过./configure –h命令来查看.--prefix=path表示设置GDAL的make install后的build目录,里面有生成的头文件和动态库.输入如下命令: ./configure --prefix=/root/Test/gdalbuild 这时可以发现目录中新生成了GD

  • Linux环境下段错误的产生原因及调试方法小结

    最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是著名的"段错误"(Segmentation Fault).借此机会系统学习了一下,这里对Linux环境下的段错误做个小结,方便以后同类问题的排查与解决. 1. 段错误是什么 一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址.访问了系统保护的内存地址.访问了只读的内存地址等等情况.这里贴一个

  • Linux下查看.so和可执行文件是否debug编译的方法(必看)

    今天同事问我,如何判断一个.so是否是debug编译的. 我记得以前自己是用file来查看一个.so,根据是否包含"not stripped"来判断该.so是否是debug编译的,于是就没做实验就回答. 然而,stripped/not stripped并不是debug/release编译的判断标准. 我对debug和release的.so运行file后,得出几乎相同的输出, 都是not stripped. 所以我算是误导同事了. 根据<Computers Systems - A

  • Linux环境下Oracle安装参数设置方法详解

    前面讲了虚拟机的设置和OracleLinux的安装,接下来我们来说下Oracle安装前的准备工作. 1.系统信息查看 系统信息查看 首先服务器ip:192.168.8.120 服务器系统:Oracle Linux Server release 6.5 服务器主机名:oracle-learn 查看磁盘空间情况: [root@oracle-learn ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/sda1 32G 4.8G 26G

  • linux环境下恢复rm误删的文件方法

    目录 前言 rm之后还有救吗 使用foremost找回文件 使用extundelete找回文件 预防误删引发的事故 总结 前言 一提到在 linux 环境下删除文件,那绝对离不开 sudo rm -rf /* 这个梗,每次看到这个命令,我都想到一幅恶搞的图片: 这个『清理垃圾』的说明真是解释的"恰到好处",据说有小白在论坛问问题,被人开玩笑的回复了 sudo rm -rf /* 这个命令,结果问题就解决了,人也拜拜了~ 从删库到跑路,一天一个入狱小技巧,所以我们一定要谨慎使用 rm -

随机推荐