• Linux学习-使用传统程序语言进行编译的简单范例


    单一程序:印出 HelloWorld

    • 编辑程序代码,亦即原始码
    [root@study ~]# vim hello.c <==用 C 语言写的程序扩展名建议用 .c
    #include <stdio.h>
    int main(void)
    {
        printf("Hello World
    ");
    }
    

    在预设的状态下,如果我们直接以 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
    ");
            thanks_2();
    }
    # 上面的 thanks_2(); 那一行就是呼叫子程序啦!
    
    [root@study ~]# vim thanks_2.c
    #include <stdio.h>
    void thanks_2(void)
    {
            printf("Thank you!
    ");
    }
    

    • 进行程序的编译与链接 (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
    ",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 之后,程序的编译会变的较为严谨一点,所以警告讯息也会显示出来!
    
  • 相关阅读:
    Sqlmap使用详解
    WEB漏洞学习手册
    量压形态的使用方法
    sql执行过程及常见优化手段
    什么是JavaScript 函数作用域
    git http 拉取代码 自动输入用户名和密码
    PHP 报文件写入无权限 file_put_contents failed to open stream: Permission denied in xxxxx on line 2
    记一次 解决PHP Linux服务器报 打开文件数过多的异常
    微信开发 坑 记录帖
    python 安装 cv2 注意事项 填坑 opencv-python 找不到指定的模块
  • 原文地址:https://www.cnblogs.com/uetucci/p/7778990.html
Copyright © 2020-2023  润新知