• 每天学五分钟 Liunx 1000 | 软件篇:源码安装



    软件安装流程

    前面软件篇提到了通过 RPM 和 YUM 在线安装的机制安装软件,除了这两种方式之外还有一种通过源码来安装软件的方式。
     
    如上流程图所示,程序员使用特定语言(c/c++/...)编写源文件,通过编译器翻译成机器可以执行的可执行文件,也就是二进制文件。其中,如果源文件依赖函数库的话,在编译的时候还需要将相应的函数库给链接上。
     
     
    走一遍操作的流程看看程序是怎么从源文件到可执行文件的。
    编写源文件 hello.cpp 和 thanks.cpp,其中 hello.cpp 引用 thanks.cpp 的函数:
    [root@lianhua tarball]$ cat hello.cpp
    #include <stdio.h>
    #include "thanks.h"
     
    int main(void)
    {
        printf("Hello World
    ");
        thanks();
     
        return 0;
    }
    [root@lianhua tarball]$ cat thanks.cpp
    #include <stdio.h>
     
    int thanks(void)
    {
        printf("thanks lianhua, I love you
    ");
     
        return 0;
    }
    [root@lianhua tarball]$ cat thanks.h
    int thanks();
     
    源文件有了,使用 Liunx 自带的 c/c++ 编译器 gcc 编译源文件:
    [root@lianhua tarball]$ gcc -c hello.cpp
    [root@lianhua tarball]$ ll
    total 16
    -rw-r--r-- 1 root root  117 May 10 22:44 hello.cpp
    -rw-r--r-- 1 root root 1560 May 10 22:45 hello.o
    -rw-r--r-- 1 root root   80 May 10 22:45 thanks.cpp
    -rw-r--r-- 1 root root   14 May 10 22:44 thanks.h
    [root@lianhua tarball]$ gcc -o hello hello.o
    hello.o: In function `main':
    hello.cpp:(.text+0xf): undefined reference to `thanks()'
    collect2: error: ld returned 1 exit status
     
    报错,显示函数 thanks 没定义。出错原因是因为 hello.cpp 引用到了该函数,但是编译的时候没有链接,所以对症下药:
    [root@lianhua tarball]$ gcc -c hello.cpp thanks.cpp
    [root@lianhua tarball]$ ll
    total 20
    -rw-r--r-- 1 root root  117 May 10 22:44 hello.cpp
    -rw-r--r-- 1 root root 1560 May 10 22:46 hello.o
    -rw-r--r-- 1 root root  100 May 10 22:46 thanks.cpp
    -rw-r--r-- 1 root root   14 May 10 22:44 thanks.h
    -rw-r--r-- 1 root root 1520 May 10 22:46 thanks.o
    [root@lianhua tarball]$ gcc -o hello hello.o thanks.o
    [root@lianhua tarball]$ ll
    total 32
    -rwxr-xr-x 1 root root 8552 May 10 22:47 hello
    -rw-r--r-- 1 root root  117 May 10 22:44 hello.cpp
    -rw-r--r-- 1 root root 1560 May 10 22:46 hello.o
    -rw-r--r-- 1 root root  100 May 10 22:46 thanks.cpp
    -rw-r--r-- 1 root root   14 May 10 22:44 thanks.h
    -rw-r--r-- 1 root root 1520 May 10 22:46 thanks.o
    [root@lianhua tarball]$ file hello
    hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=1801febeffa3328a578dac21ee994dd50893ed3f, not stripped
    [root@lianhua tarball]$ ./hello
    Hello World
    thanks lianhua, I love you
     
    可以看到,将 thanks.cpp 编译成目标文件 thanks.o,然后链接到该目标文件生成了可执行的二进制文件 hello。其中,file 命令可以判断文件是二进制文件或一般文本文件。
     
     
    这是一种生成可执行文件的方式,还有一种提供函数库给编译器编译的方式。
    函数库分两种静态函数库和动态函数库,静态函数库在编译的时候被放到可执行文件中,动态函数库在编译的时候会创建“指针”指向该动态函数库。所以,使用静态函数库的可执行文件要比使用动态函数库的可执行文件大。但是基于静态函数库的可执行文件在编译完之后就不依赖于库,放到哪都可以执行,基于动态函数库的可执行文件则不行,它需要能引用到该动态函数库。

    静态函数库的可执行文件

    [root@lianhua tarball]$ ar rcs liblianhua.a thanks.o
    [root@lianhua tarball]$ ll
    total 36
    ...
    -rw-r--r-- 1 root root 1668 May 10 23:09 liblianhua.a
    [root@lianhua tarball]$ gcc hello.cpp -llianhua -L/root/hxia/tarball
    [root@lianhua tarball]$ gcc hello.cpp -llianhua -L/root/hxia/tarball -o lianhua
    [root@lianhua tarball]$ ll
    total 60
    -rwxr-xr-x 1 root root 8552 May 10 22:47 hello
    -rw-r--r-- 1 root root  117 May 10 22:44 hello.cpp
    -rw-r--r-- 1 root root 1560 May 10 22:46 hello.o
    -rwxr-xr-x 1 root root 8552 May 10 23:11 lianhua
    -rw-r--r-- 1 root root 1668 May 10 23:09 liblianhua.a
    -rw-r--r-- 1 root root  100 May 10 22:46 thanks.cpp
    -rw-r--r-- 1 root root   14 May 10 22:44 thanks.h
    -rw-r--r-- 1 root root 1520 May 10 22:46 thanks.o
    [root@lianhua tarball]$ ./lianhua
    Hello World
    thanks lianhua, I love you
     
    通过 ar 命令将 thanks.o 生成为 lianhua 的静态函数库,编译器链接该静态函数库生成可执行的二进制文件 lianhua。其中,静态函数库以 .a 结尾,动态函数库以 .so 结尾。

    动态函数库的可执行文件

    [root@lianhua shared]$ gcc -fPIC -shared thanks.cpp -o liblianhua.so
    [root@lianhua shared]$ ll
    total 20
    -rw-r--r-- 1 root root  117 May 10 23:18 hello.cpp
    -rwxr-xr-x 1 root root 8112 May 10 23:20 liblianhua.so
    -rw-r--r-- 1 root root  100 May 10 23:18 thanks.cpp
    -rw-r--r-- 1 root root   14 May 10 23:18 thanks.h
    [root@lianhua shared]$ gcc hello.cpp -L. -llianhua -o hello
    [root@lianhua shared]$ ll
    total 32
    -rwxr-xr-x 1 root root 8528 May 10 23:21 hello
    -rw-r--r-- 1 root root  117 May 10 23:18 hello.cpp
    -rwxr-xr-x 1 root root 8112 May 10 23:20 liblianhua.so
    -rw-r--r-- 1 root root  100 May 10 23:18 thanks.cpp
    -rw-r--r-- 1 root root   14 May 10 23:18 thanks.h
    [root@lianhua shared]$ ./hello
    ./hello: error while loading shared libraries: liblianhua.so: cannot open shared object file: No such file or directory
     
    命令 gcc -fPIC -shared 将 thanks.cpp 编译成动态函数库 lianhua,生成可执行文件 hello。但是,在执行 hello 的时候报错了,提示找不到 lianhua 这个动态函数库。错误原因是动态链接时默认从 /usr/lib 目录下找动态函数库,将 lianhua 拷到该目录下,更新配置:
    [root@lianhua shared]$ cp libthanks.so /usr/lib/
    [root@lianhua shared]$ vi /etc/ld.so.conf
    [root@lianhua shared]$ ldconfig
    [root@lianhua shared]$ ./hello
    Hello World
    thanks lianhua, I love you
     
    ldconfig 命令将动态函数库从硬盘加载到内存中,这样执行可执行文件的时候执行引用内存中的动态函数库,速度会快很多。
     
    Liunx 的 ldd 命令可以查看可执行文件引用了哪些动态函数库:
    [root@lianhua tarball]$ ldd hello
            linux-vdso.so.1 =>  (0x00007ffcc9bec000)
            libc.so.6 => /lib64/libc.so.6 (0x00007f4175126000)
            /lib64/ld-linux-x86-64.so.2 (0x00007f41754f3000)
    [root@lianhua tarball]$ ldd ./shared/hello
            linux-vdso.so.1 =>  (0x00007fff7d9da000)
            libthanks.so => /lib/libthanks.so (0x00007f6896b53000)
            libc.so.6 => /lib64/libc.so.6 (0x00007f6896786000)
            /lib64/ld-linux-x86-64.so.2 (0x00007f6896d55000)
    可以发现基于动态函数库的 hello 指向了 thanks 这个库。同时,比较两个可执行文件大小也会发现基于静态函数库的可执行文件 hello 要比基于动态函数库的可执行文件要大。
     
     
    想象下,这是只有一个函数的编译情况,在实际项目中有成百上千上万个函数,各个函数分布在不同的目录这时候在用这种 gcc 指定函数库编译的方式就特别不适用了。
    在这种情况下,会写 cmake 文件定义编译规则,每个目录下都有 cmake 文件。再执行 cmake 命令生成 makefile 文件,然后通过 make 命令就能根据 makefile 中的规则编译生成可执行文件。
     
    具体这个流程实操不介绍了,有兴趣的看看这个文档
     
     
     
    (完)
     
  • 相关阅读:
    kafka 控制台命令
    VMware centos7 如何配置静态ip并且可上网
    kafka学习-坑篇
    IDEA中Git的更新、提交、还原方法
    深入理解Java的接口和抽象类
    java动态代理实现与原理详细分析
    注解 @EnableFeignClients 工作原理
    com.mysql.cj.jdbc.Driver 新特性jdbc.url连接供参考
    插入数据库中文乱码
    logback配置文件
  • 原文地址:https://www.cnblogs.com/xingzheanan/p/12866488.html
Copyright © 2020-2023  润新知