`
CJxixi
  • 浏览: 106678 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Linux 下编译C程序

 
阅读更多

GCC 已不再是主要针对GNU项目自身的软件的小型 C
语言编译器了。如今,它已支持了许多不同的语言,包括
C、C++、Ada、Fortran、Objective C,甚至还有Java。事实上,现代 Linux
系统除了可以自豪地炫耀那些由 GNU
工具直接支持的语言以外,它还支持大量其他语言。日益流行的脚本语言
Perl、Python 和 Ruby,以及正在不断发展的mono
可移植C#实现的确有助于冲淡人们对 Linux
编程的传统看法,但这完全是另外一个问题了。

Linux 内核和许多其他自由软件以及开放源码应用程序都是用 C 语言编写并使用
GCC 编译的。

1. 编译单个源文件

为了进行测试,你可以创建"Hello World"程序:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
printf("Hello world!\n");
exit(0);
}

使用如下命令编译并测试这个代码:
# gcc -o hello hello.c
# ./hello
Hello wordl!

在默认情况下产生的可执行程序名为a.out,但你通常可以通过 gcc
的"-o"选项来指定自己的可执行程序名称。

2. 编译多个源文件

源文件message.c包含一个简单的消息打印函数:

#include <stdio.h>

void goodbye_world(void)
{
printf("Goodbye, world!\n");
}

使用gcc的"-c"标记来编译支持库代码:
# gcc -c message.c

这一过程的输出结果是一个名为message.o的文件,它包含适合连接到一个较大程序的已编译目标代码。

创建一个简单的示例程序,它包含一个调用goodbye_world的main函数

#include <stdlib.h>

void goodbye_world(void):

int main(int argc, char **argv)
{
goodbye_world();
exit(0);
}

使用GCC编译这个程序:
# gcc -c main.c

现在有了两个目标文件: message.o 和 main.o 。它们包含能够被 Linux
执行的目标代码。要从这个目标代码创建Linux可执行程序,需要再一次调用 GCC
来执行连接阶段的工作:
# gcc -o goodbye message.o main.o

运行编译结果:
# ./goodbye
Goodbye, world!

前面这些单独的步骤也可以简化为一个命令,这是因为 GCC
对如何将多个源文件编译为一个可执行程序有内置的规则。
# gcc -o goodbye message.c main.c
# ./goodbye
Goodbye, world!

3. 使用外部函数库

GCC 常常与包含标准例程的外部软件库结合使用,几乎每一个 Linux
应用程序都依赖于由 GNU C 函数库 GLIBC。
应用外部函数库的例子:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define MAX_INPUT 25

int main(int agrc, char **argv)
{
char input[MAX_INPUT];
double angle;

printf("Give me an angle (in radians) ==>");
if(!fgets(input, MAX_INPUT, stdin)){
perror("an error occurred.\n");
}
angle = strtod(input, NULL);

printf("sin(%e) = %e\n", angle, sin(angle));

return 0;
}

编译命令:
# gcc -o trig -lm trig.c

GCC 的"-lm"选项,它告诉 GCC
查看系统提供的数学库(libm)。因为Linux和UNIX的系统函数库通常以"lib"为前缀,所以我们假设它存在。真正的函数库位置随系统的不同而
不同,但它一般会位于目录/lib或/usr/lib中,在这些目录中还有数以百计的其他必需的系统函数库。

4. 共享函数库与静态函数库

Linux系统上的函数库分为两种不同的类型:共享的和静态的

静态函数库:每次当应用程序和静态连接的函数库一起编译时,任何引用的库函数中的代码都会被直接包含进最终的二进制程序。

共享函数库:包含每个库函数的单一全局版本,它在所有应用程序之间共享。这一过程背后所涉及的机制相当复杂,但主要依靠的是现代计算机的虚拟内存能力,它允许包含库函数的物理内存安全地在多个独立用户程序之间共享。

使用共享函数库不仅减少了文件的容量和 Linux
应用程序在内存中覆盖的区域,而且它还提高了系统的安全性。一个被许多不同程序同时调用的共享函数库很可能会驻留在内存中,以在需要使用它时被立即使用,
而不是位于磁盘的交换分区中。这有助于进一步减少一些大型 Linux
应用程序的装载时间。

将上面的 message.c 作为共享库函数使用的例子:

# gcc -fPIC -c message.c
"PIC"命令行标记告诉 GCC
产生的代码不要包含对函数和变量具体内存位置的引用,这是因为现在还无法知道使用该消息代码的应用程序会将它连接到哪一段内存地址空间。这样编译输出的文
件 message.o 可以被用于建立共享函数库,我们只需使用gcc的"-shared"标记即可:
# gcc -shared -o libmessage.so message.o

将上面的mian.c使用共享库函数ligmessage.so 编译:
# gcc -o goodbye -lmessage -L. message.o
"-lmessage"标记来告诉 GCC 在连接阶段引用共享函数库 libmessage.so
。"-L."标记告诉 GCC 函数库可能位于当前目录中,否则 GNU
的连接器会查找标准系统函数库目录,在本例的情况下,就找不到可用的函数库了。

此时运行编译好的goodbye会提示找不到共享函数库:
#./goodbye
./goodbye: error while loading shared libraries: libmessage.so: cannot
open shared object file: No such file or directory

可以使用命令 ldd
来发现一个特定应用程序需要使用的函数库。ldd搜索标准系统函数库路径并显示一个特定程序使用的函数库版本。

#ldd goodbye
linux-gate.so.1 => (0×00493000)
libmessage.so => not found
libc.so.6 => /lib/libc.so.6 (0×0097c000)
/lib/ld-linux.so.2 (0×0095a000)

库文件 libmessage.so
不能在任何一个标准搜索路径中找到,而且系统提供的配置文件 /etc/ld.so.conf
也没有包含一个额外的条目来指定包含该库文件的目录。

需要设置一个环境变量LD_LIBRARY_PATH来制定额外的共享函数库搜索路径,
# export LD_LIBRARY_PATH=`pwd`
# ldd goodbye
linux-gate.so.1 => (0x002ce000)
libmessage.so => /tmp/cpro/libmessage.so (0x00b0f000)
libc.so.6 => /lib/libc.so.6 (0x0097c000)
/lib/ld-linux.so.2 (0x0095a000)
运行程序
# ./goodbye
Goodbye, world!

gcc在命令行上经常使用的几个选项是:
-c
只预处理、编译和汇编源程序,不进行连接。编译器对每一个源程序产生一个目标文件。
-o file 确定输出文件为file。如果没有用-o选项,缺省的可执行文件的输出是
a.out,目标文件和汇编文件的输出对source.suffix分别是source.o和source.s,预处理的C源程序的输出是标准输出stdout。
-Dmacro或-Dmacro=defn 其作用类似于源程序里的#define。例如:% gcc -c
-DHAVE_GDBM -DHELP_FILE=\"help\" cdict.c其中第一个-
D选项定义宏HAVE_GDBM,在程序里可以用#ifdef去检查它是否被设置。第二个-D选项将宏HELP_FILE定义为字符串"help"(由于
反斜线的作用,引号实际上已成为该宏定义的一部分),这对于控制程序打开哪个文件是很有用的。
-Umacro
某些宏是被编译程序自动定义的。这些宏通常可以指定在其中进行编译的计算机系统类型的符号,用户可以在编译某程序时加上
-v选项以查看gcc缺省定义了哪些宏。如果用户想取消其中某个宏定义,用-Umacro选项,这相当于把#undef
macro放在要编译的源文件的开头。
-Idir
将dir目录加到搜寻头文件的目录列表中去,并优先于在gcc缺省的搜索目录。在有多个-I选项的情况下,按命令行上-I选项的前后顺序搜索。dir可使用相对路径,如-I../inc等。
-O
对程序编译进行优化,编译程序试图减少被编译程序的长度和执行时间,但其编译速度比不做优化慢,而且要求较多的内存。
-O2 允许比-O更好的优化,编译速度较慢,但结果程序的执行速度较快。
-g
产生一张用于调试和排错的扩展符号表。-g选项使程序可以用GNU的调试程序GDB进行调试。优化和调试通常不兼容,同时使用-g和-O(-O2)选项经常会使程序产生奇怪的运行结果。所以不要同时使用-g和-O(-O2)选项。
-fpic或-fPIC 产生位置无关的目标代码,可用于构造共享函数库。
以上是gcc的编译选项。gcc的命令行上还可以使用连接选项。事实上,gcc将所有不能识别的选项传递给连接程序ld。连接程序ld将几个目标文件和库
程序组合成一个可执行文件,它要解决对外部变量、外部过程、库程序等的引用。但我们永远不必要显式地调用ld。利用gcc命令去连接各个文件是很简单的,
即使在命令行里没有列出库程序,gcc也能保证某些库程序以正确的次序出现。
gcc的常用连接选项有下列几个:
-Ldir
将dir目录加到搜寻-l选项指定的函数库文件的目录列表中去,并优先于gcc缺省的搜索目录。在有多个-L选项的情况下,按命令行上-L选项的前后顺序搜索。dir可使用相对路径。如-L../lib等。
-lname
在连接时使用函数库libname.a,连接程序在-Ldir选项指定的目录下和/lib,/usr/lib目录下寻找该库文件。在没有使用-static选项时,如果发现共享函数库libname.so,则使用libname.so进行动态连接。
-static 禁止与共享函数库连接。
-shared 尽量与共享函数库连接。
这是Linux上连接程序的缺省选项。下面是一个使用gcc进行连接的例子:
% gcc -o prog main.o subr.o -L../lib -lany -lm

分享到:
评论

相关推荐

    linux下GCC编译C程序

    【GCC编译C程序】是Linux环境中开发C语言软件的核心环节。GNU编译器集(GCC),最初称为GNU C编译器,由Richard Stallman在1987年发起,旨在构建符合自由软件理念的编译器,用于构建GNU项目中的其他软件。GCC很快因...

    linux驱动程序编译以及应用程序编译

    Linux 驱动程序编译和应用程序编译 Linux 驱动程序编译是指将驱动程序源代码编译成可加载到 Linux 内核的模块,以便控制和管理硬件设备。编译过程中需要使用交叉编译器 arm-linux-gcc,将驱动程序编译成模块并安装...

    如何在Linux下用gcc编译c程序

    对于初学者或专业人士而言,掌握如何在Linux环境下使用gcc编译C程序是至关重要的。下面我们将详细探讨这个过程及其相关知识点。 首先,要开始编译C程序,你需要确保你的Linux系统已经安装了GCC。你可以通过运行`gcc...

    LINUX下多个c程序编译链接的程序

    本主题将深入探讨如何在Linux下有效地编译和链接多个C程序,并结合`makefile`来自动化这个过程。 首先,理解C程序的编译和链接是至关重要的。编译是将源代码(`.c`文件)转换为中间目标代码(`.o`文件)的过程,而...

    在deepin深度系统中编译C语言程序

    `build-essential`是一个包含了一系列基础编译工具的软件包,它包括了GCC(GNU Compiler Collection)和Make等,这些都是在Linux环境下编译C语言程序所必需的。在Deepin系统中,你可以通过打开终端并输入以下命令来...

    第一讲 Linux下C语言程序开发

    " Linux下C语言程序开发详解" 本资源主要讲解了 Linux 下 C 语言程序开发的基础知识和基本概念。课程的主要内容包括 Linux 操作系统和 C 语言简介、Linux 下 C 语言程序开发的基础知识、虚拟机的使用、基本开发过程...

    在Linux下编译并运行C程序

    GCC主要用于编译C语言程序,而G++则专门用于编译C++程序。 要安装这些编译工具,可以使用Linux发行版自带的包管理器。例如,在基于Debian的发行版(如Ubuntu)中,可以通过以下命令安装: ```bash sudo apt-get ...

    Linux下编译C程序的过程

    学习一门语言程序,本人觉得还是得学习它的编译规则,现在,通过小例子小结下自己对C编译的认识。 /*test.c 了解C程序的编译*/ #include int main(void) { printf(Hello World!\n); return 0; } 对于test.c,...

    linux中如何编译C程序

    本文将详细介绍如何在Linux环境下编写、编译和运行C语言程序。 首先,你需要一个文本编辑器来创建C程序。在示例中提到了`vi`编辑器,但也可以使用其他如`nano`或`gedit`等更友好的文本编辑器。例如,你可以通过以下...

    Linux系统中如何编译C程序

    主要是Linux系统中如何编译C程序,实现对linux内核的掌控与增加系统调用。

    Cython文件在window与linux下的编译指导

    Cython 文件在 window 与 linux 下的编译指导 Cython 文件在 window 与 linux 下的编译指导是指在不同的操作系统平台上编译 Cython 文件的指导。Cython 是一种高级语言,可以将 Python 代码编译成 C 代码,然后再...

    Linux_下编译程序的三种方式

    在Linux环境下,编译程序通常有三种主要方式:直接使用GCC编译器、利用Make工具以及使用特定的构建系统如Autotools或CMake。下面将详细解释这三种方法。 ### 1. GCC编译器 GCC(GNU Compiler Collection)是Linux...

    LINUX 下C语言使用、编译与调试实...

    Linux 下 C 语言使用、编译与调试 Linux 是一个开源的操作系统,广泛应用于服务器、嵌入式系统和个人电脑等领域。作为一个程序员,熟悉 Linux 下的 C 语言开发环境是非常重要的。本资源将引导读者学习如何使用 vi ...

    在Linux下编译程序示例

    本文将深入探讨如何在Linux环境下编译程序,包括使用GCC(GNU Compiler Collection)编译器、GDB调试工具以及相关的编译步骤。 首先,让我们了解一下GCC。GCC是GNU项目的一部分,它提供了C、C++、Objective-C、...

    linux操作系统下C语言编程入门 gcc编译

    在Linux环境中,主要使用GNU的`gcc`编译器来编译C语言程序。`gcc`是一个功能强大的编译器,支持多种编程语言,包括C、C++等,并且提供了丰富的选项供开发者使用。 **示例**: 以一个简单的“Hello World”程序为例:...

    Visual Studio 2010 编译C及一个完整的c程序(可在windows与linux(用gcc编译)平台下使用)

    标题中的“Visual Studio 2010 编译C及一个完整的c程序”指的是使用Microsoft Visual Studio 2010这个集成开发环境(IDE)来编写和编译C语言程序。Visual Studio 2010提供了强大的代码编辑器、调试工具和项目管理...

    linux下程序的编译及调试

    本篇文章将详细探讨这两个方面,并以`pstack`工具为例,介绍如何在Linux环境下进行程序的编译与调试。 首先,让我们来理解一下编译过程。在Linux下,最常用的编译器是GCC(GNU Compiler Collection)。当编写好C或...

    Linux下使用codeblocks交叉编译ARM-LINUX-GCC程序

    Linux 下使用 CodeBlocks 交叉编译 ARM-LINUX-GCC 程序 在这个资源中,我们将学习如何使用 CodeBlocks 在 Linux 平台下交叉编译 ARM-LINUX-GCC 程序。交叉编译是一种在不同的平台之间编译代码的技术,能让开发者在...

    在Linux下编译程序讲义

    本讲义将深入探讨如何在Linux环境下编译程序,包括使用GCC(GNU Compiler Collection)工具链,理解编译过程,以及利用GDB(GNU Debugger)进行调试。以下是对这些主题的详细阐述: 1. **Linux环境**:Linux是一种...

Global site tag (gtag.js) - Google Analytics