Linux学习-使用传统程序语言进行编译的简单范例
单一程序:印出 HelloWorld
- 编辑程序代码,亦即原始码
[root@study ~]# vim hello.c <==用 C 语言写的程序扩展名建议用 .c
#include <stdio.h>
int main(void)
{
printf("Hello World\n");
}
在预设的状态下,如果我们直接以 gcc 编译原始码,并且没有加上任何参数,则执行档的档名会被 自动设定为 a.out 这个文件名!所以妳就能够直接执行 ./a.out 这个执行档啦!那如果我想要产生目标文件 (object file) 来进行其他的动作,而且执行档的档名也不要用 预设的 a.out ,那该如何是好?其实妳可以将上面的第 2 个步骤改成这样:
[root@study ~]# gcc -c hello.c
[root@study ~]# ll hello*
-rw-r--r--. 1 root root 71 Sep 4 11:32 hello.c
-rw-r--r--. 1 root root 1496 Sep 4 11:34 hello.o <==就是被产生的目标文件
[root@study ~]# gcc -o hello hello.o
[root@study ~]# ll hello*
-rwxr-xr-x. 1 root root 8503 Sep 4 11:35 hello <==這就是可執行檔! -o 的結果
-rw-r--r--. 1 root root 71 Sep 4 11:32 hello.c
-rw-r--r--. 1 root root 1496 Sep 4 11:34 hello.o
[root@study ~]# ./hello
Hello World
这个步骤主要是利用 hello.o 这个目标文件制作出一个名为 hello 的执行文件,
主、子程序链接:子程序的编译
如果我们在一个主程序里面又呼叫了另一个子程序呢?这是很常见的一个程序写法, 因为可以简化整个程序的易读性!在底下的例子当中,我们以 thanks.c 这个主程序去呼叫 thanks_2.c 这个子程序,写法很简单:
- 撰写所需要的主、子程序
# 1. 编辑主程序:
[root@study ~]# vim thanks.c
#include <stdio.h>
int main(void)
{
printf("Hello World\n");
thanks_2();
}
# 上面的 thanks_2(); 那一行就是呼叫子程序啦!
[root@study ~]# vim thanks_2.c
#include <stdio.h>
void thanks_2(void)
{
printf("Thank you!\n");
}
- 进行程序的编译与链接 (Link)
# 2. 开始将原始码编译成为可执行的 binary file :
[root@study ~]# gcc -c thanks.c thanks_2.c
[root@study ~]# ll thanks*
-rw-r--r--. 1 root root 75 Sep 4 11:43 thanks_2.c
-rw-r--r--. 1 root root 1496 Sep 4 11:43 thanks_2.o <==编译产生的!
-rw-r--r--. 1 root root 91 Sep 4 11:42 thanks.c
-rw-r--r--. 1 root root 1560 Sep 4 11:43 thanks.o <==编译产生的!
[root@study ~]# gcc -o thanks thanks.o thanks_2.o
[root@study ~]# ll thanks*
-rwxr-xr-x. 1 root root 8572 Sep 4 11:44 thanks <==最终结果会产生这玩意儿
# 3. 执行一下这个文件:
[root@study ~]# ./thanks
Hello World
Thank you!
知道为什么要制作出目标文件了吗?由于我们的原始码文件有时并非仅只有一个文件,所以我们无法 直接进行编译。这个时候就需要先产生目标文件,然后再以连结制作成为 binary 可执行文件。另外, 如果有一天,你更新了 thanks_2.c 这个文件的内容,则你只要重新编译 thanks_2.c 来产生新的 thanks_2.o ,然后再以连结制作出新的 binary 可执行文件即可!而不必重新编译其他没有更动过的 原始码文件。
此外,如果你想要让程序在执行的时候具有比较好的效能,或者是其他的除错功能时, 可以在编译 的过程里面加入适当的参数,例如底下的例子:
[root@study ~]# gcc -O -c thanks.c thanks_2.c <== -O 为产生优化的参数
[root@study ~]# gcc -Wall -c thanks.c thanks_2.c
thanks.c: In function ‘main’:
thanks.c:5:9: warning: implicit declaration of function ‘thanks_2’ [-Wimplicit-function-declaration]
thanks_2();
^
thanks.c:6:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
# -Wall 为产生更详细的编译过程信息。上面的讯息为警告讯息 (warning) 所以不用理会也没有关系!
呼叫外部函式库:加入连结的函式库
刚刚我们都仅只是在屏幕上面印出一些字眼而已,如果说要计算数学公式呢?例如我们想要计算出三 角函数里面的 sin (90 度角)。要注意的是,大多数的程序语言都是使用径度而不是一般我们在计算的 『角度』, 180 度角约等于 3.14 径度!嗯!那我们就来写一下这个程序吧!
[root@study ~]# vim sin.c
#include <stdio.h>
#include <math.h>
int main(void)
{
float value;
value = sin ( 3.14 / 2 );
printf("%f\n",value);
}
那要如何编译这支程序呢?我们先直接编译看看:
[root@study ~]# gcc sin.c
# 新的 GCC 会主动将函数抓进来给你用,所以只要加上 include <math.h> 就好了!
新版的 GCC 会主动帮你将所需要的函式库抓进来编译,所以不会出现怪异的错误讯息! 事实上, 数学函式库使用的是 libm.so 这个函式库,你最好在编译的时候将这个函式库纳进去比较好~另外要 注意, 这个函式库放置的地方是系统默认会去找的 /lib, /lib64 ,所以你无须使用底下的 -L 去加入 搜寻的目录! 而 libm.so 在编译的写法上,使用的是 -lm
- 编译时加入额外函式库连结的方式:
[root@study ~]# gcc sin.c -lm -L/lib -L/lib64 <==重点在 -lm
[root@study ~]# ./a.out <==尝试执行新文件!
1.000000
特别注意,使用 gcc 编译时所加入的那个 -lm 是有意义的,他可以拆开成两部份来看:
- -l :是『加入某个函式库(library)』的意思,
- m :则是 libm.so 这个函式库,其中, lib 与扩展名(.a 或 .so)不需要写
所以 -lm 表示使用 libm.so (或 libm.a) 这个函式库的意思~至于那个 -L 后面接的路径呢?这表示: 『我要的函式库 libm.so 请到 /lib 或 /lib64 里面搜寻!』
除了连结的函式库之外,你或许已经发现一个奇怪的地方,那就是在我们的 sin.c 当中第一行『 #include <stdio.h>』,这行说的是要将一些定义数据由 stdio.h 这个文件读入,这包括 printf 的相关设定。这个文件其实是放置在 /usr/include/stdio.h 的!那么万一这个文件并非放置在这里呢?那 么我们就可以使用底下的方式来定义出要读取的 include 文件放置的目录:
[root@study ~]# gcc sin.c -lm -I/usr/include
-I/path 后面接的路径( Path )就是设定要去搜寻相关的 include 文件的目录。不过,同样的,默认值 是放置在 /usr/include 底下,除非你的 include 文件放置在其他路径。
gcc 的简易用法 (编译、参数与链结)
底下我们就列举 几个 gcc 常见的参数,如此一来大家应该更容易了解原始码的各项功能吧!
# 仅将原始码编译成为目标文件,并不制作链接等功能:
[root@study ~]# gcc -c hello.c
# 会自动的产生 hello.o 这个文件,但是并不会产生 binary 执行档。
# 在编译的时候,依据作业环境给予优化执行速度
[root@study ~]# gcc -O hello.c -c
# 会自动的产生 hello.o 这个文件,并且进行优化喔!
# 在进行 binary file 制作时,将连结的函式库与相关的路径填入
[root@study ~]# gcc sin.c -lm -L/lib -I/usr/include
# 这个指令较常下达在最终连结成 binary file 的时候,
# -lm 指的是 libm.so 或 libm.a 这个函式库文件;
# -L 后面接的路径是刚刚上面那个函式库的搜寻目录;
# -I 后面接的是原始码内的 include 文件之所在目录。
# 将编译的结果输出成某个特定档名
[root@study ~]# gcc -o hello hello.c
# -o 后面接的是要输出的 binary file 檔名
# 在编译的时候,输出较多的讯息说明
[root@study ~]# gcc -o hello hello.o -Wall
# 加入 -Wall 之后,程序的编译会变的较为严谨一点,所以警告讯息也会显示出来!
Linux学习-使用传统程序语言进行编译的简单范例的更多相关文章
- Linux学习笔记—vim程序编辑器
vi和vim vim是vi的升级版,支持vi的所有指令 vi的使用 vi分为三种模式:一般模式.编辑模式.命令行模式 一般模式 以vi打开一个文件就直接进入一般模式了,这个模式下可以使用上下左右按键来 ...
- [Linux]方便openmp等程序的类似编译
因为总是打参数例如-fopenmp或者-lGL等等有些麻烦,所以特地写一个可以使用的bash文件用来执行简单的操作 首先在.profile中添加 if [ -d "$HOME/bin&quo ...
- Linux环境下用C语言实现socket 通信---简单代码
Socket编程实例: 服务器端:一直监听本机的8000号端口,如果收到连接请求,将接收请求并接收客户端发来的消息,并向客户端返回消息. 客户端:client.c /* File Name: clie ...
- Linux学习总结(十八)几个简单的文本处理工具cut sort tr split
1 命令cut 用来截取某一个字段格式 : cut -d '分隔符' [-cf] n, n为数字,表示第几段-d:后面跟分隔符,分割符要加单引号-c:后面接的是第几个字符-f:后面接的是第几段那么意思 ...
- linux学习书籍推荐《鸟哥的Linux私房菜》下载
下载地址:点我 <鸟哥的Linux私房菜:基础学习篇>是具有知名度的Linux入门书<鸟哥的Linux私房菜基础学习篇>的最新版,全面而详细地介绍了Linux操作系统.< ...
- 简单易懂的程序语言入门小册子(1):基于文本替换的解释器,lambda演算
最近比较闲,打算整理一下之前学习的关于程序语言的知识.主要的内容其实就是一边设计程序语言一边写解释器实现它.这些知识基本上来自Programming Languages and Lambda Calc ...
- linux应用程序设计--GCC程序编译
GCC程序编译 linux系统下的GCC(GNU C Compiler)是GNU推出的功能强大.性能优越的多平台编译器,是GNU的代表作之一.GCC可以在多种硬件平台上编译出可执行程序,其执行效率与一 ...
- Linux C 程序 空语句-gcc编译命令(SIX)
C语言语句1.空语句:当一个if或者while判断部分能完成工作,空语句可以用来表示if或者while内的空循环体 if(a == b ); 2.gcc编译器 //程序的编译过程: // 预处理:pr ...
- Linux学习-核心编译的前处理与核心功能选择
硬件环境检视与核心功能要求 根据自己的需求来确定编译的选项 保持干净原始码: make mrproper 我们还得要处理一下核心原始码底下的残留文件才行!假设我们是第一次 编译, 但是我们不清楚到底下 ...
随机推荐
- nodejs 实践:express 最佳实践(三) express 解析
nodejs 实践:express 最佳实践(三) express 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固, ...
- FirstAFNetWorking
// ViewController.h // FirstAFNetWorking // // Created by 张国锋 on 15/7/20. // Copyright (c) 2015年 张国锋 ...
- Collections集合工具类,集合嵌套,集合综合案例斗地主
1 Collections集合工具类 (可以对比Arrays工具类共同记忆) 常用方法: 例: import java.util.ArrayList; import java.util.Collect ...
- IDEA SpringBoot +thymeleaf配置
1.pom添加以下依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactI ...
- Gradle项目构建(1)——Gradle的由来
一.项目自动构建介绍 作为Java的开发者对eclipse都非常熟悉,其实eclipse就是居于ant来构建项目的,我们先来看看为什么需要自动化构建项目. 1.为什么我们要自动化构建项目 可以假设我们 ...
- 【虚拟机-虚拟网络】使用 PsPing & PaPing 进行 TCP 端口连通性测试
PsPing & PaPing 介绍 通常,我们测试数据包能否通过 IP 协议到达特定主机时,都习惯使用 ping 命令.工作时 ping 向目标主机发送一个 IMCP Echo 请求的数据包 ...
- HDU 2147 kiki's game kiki的游戏(博弈,找规律)
题意: 给一个有n*m 个格子的棋盘,将一个硬币放在右上角一格,每次可以往左/下/左下移动一格,碰到不能移动的局面者输. 思路: 找P/N状态.先将(n,1)归为P状态,那么能一步到达此位置的有3个位 ...
- 协议学习之 vamei博客系列 总结
1. 分层: 物理层(physical layer) 所谓的物理层,是指光纤.电缆或者电磁波等真实存在的物理媒介.这些媒介可以传送物理信号,比如亮度.电压或者振幅.对于数字应用来说,我们只需要两种物理 ...
- UI高端课程
目后佐道IT教育正在打架报名中,欢迎高中生.大学生前来学习编程技术和UI设计,招生面向全国. 石破天惊 前100个报名者免费提供高级公寓居住(里面有空调,暖气,热水器,洗衣机). 赠送神秘课程价值29 ...
- C、C++、C#中struct的简单比较
比较这三者是因为C.C++.C#这三者存在着一定的血缘关系,而他们三者都有的struct却有很大的不同. 功能 C中的struct是最简单的.只能有成员变量而不能有成员函数. C++和C#中都支持,而 ...