评论

收藏

[C++] GCC入门

编程语言 编程语言 发布于:2021-07-01 12:32 | 阅读数:433 | 评论:0

  gcc使用
  gcc编译过程
DSC0000.png

选项名作用
-o产生目标(.i、.s、.o、可执行文件等)
-E只运行C预编译器
-S告诉编译器产生汇编程序文件后停止编译,产生的汇编语言文件拓展名为.s
-c通知gcc取消连接步骤,即编译源码,并在最后生成目标文件
-w不产生任何警告信息
-Wall使gcc对源文件的代码有问题的地方发出警告
-Idir指定 include 包含文件的搜索目录
-Ldir指定编译的时候,搜索的库的路径。
-lLib在程序编译的时候,指定使用的库
-g在目标文件中嵌入调试信息,以便gdb之类的调试程序调试
-D允许从编译程序命令行进行宏定义符号
  gcc的使用示例:
gcc -E hello.c -o hello.i   对hello.c文件进行预处理,生成了hello.i 文件
gcc -S hello.i -o hello.s  对预处理文件进行编译,生成了汇编文件
gcc -c hello.s -o hello.o  对汇编文件进行编译,生成了目标文件
gcc hello.o -o hello 对目标文件进行链接,生成可执行文件
gcc hello.c -o hello 直接编译链接成可执行目标文件
gcc -c hello.c 或 gcc -c hello.c -o hello.o 编译生成可重定位目标文件
gcc编译多个文件
  test目录下有是哪个文件hello.c hello.h main.c ,三个文件的内容如下:
// hello.c
#include<stdio.h>
#include"hello.h"
void printHello()
{
    printf("hello world!\n");
}
//main.c
#include<stdio.h>
#include"hello.h"
int main()
{
    printHello();
    return 0;
}
//hello.h
//仅包含函数声明
#ifndef _HELLO_
#define _HELLO_
void printHello();
#endif
  编译这三个文件,可以一次编译生成可执行文件main:
gcc hello.c main.c -o main

  • 通过脚本可以实现编译
#!/bin/bash
gcc hello.c main.c -o main
  也可以独立编译:
gcc -Wall -c main.c -o main.o
 gcc -Wall -c hello.c -o hello.o
 gcc -Wall main.o hello.o -o main1

  • 脚本编译
#!/bin/bash
gcc -Wall -c main.c -o main.o
gcc -Wall -c hello.c -o hello.o
gcc -Wall main.o hello.o -o main1

echo "install main1"

sudo cp ./main1 /usr/bin   #执行这步可以在任意目录下运行main1这个程序
  独立编译的好处是,当其中某个模块发送改变时,只需要编译该模块就行,不必重新编译所有文件,这样可以节省编译时间。
使用外部库
  静态库与动态库:
  • 静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库。静态库比较占用磁盘空间,而且程序不可以共享静态库。运行时也是比较占内存的,因为每个程序都包含了一份静态库。
  • 动态库(.so或.sa):程序在运行的时候才去链接共享库的代码,多个程序共享使用库的代码,这样就减少了程序的体积。
  一般头文件或库文件的位置在:
  • /usr/include及其子目录底下的include文件夹
  • /usr/local/include及其子目录底下的include文件夹
  • /usr/lib
  • /usr/local/lib
  • /lib
生成静态库
  • 为了生成.a文件,我们需要先生成.o文件。下面这行命令将我们的hello.o打包成静态库libhello.a:
ar rcs libhello.a hello.o
  ar是gun归档工具,rcs表示replace and create,如果libhello之前存在,将创建新的libhello.a并将其替换。
  r - 将文件插入备存文件中
  c - 建立备存文件
  s - 索引
  • 然后就可以这样来使用静态库libhello.a
gcc -Wall main.c libhello.a -o main
生成共享库(动态库)
  • 生成一个共享库,名称的规则是libxxx.so。将刚才hello.o生成libhello.so的命令为:
gcc hello.c -fPIC -shared -o libhello.ao
#gcc -shared -fPIC hello.c -o libhello.so
deroy@ubuntu:~/work/test$ ls
hello.c  hello.h  hello.o  libhello.a  main  main.c
deroy@ubuntu:~/work/test$ gcc hello.c -fPIC -shared -o libhello.ao
deroy@ubuntu:~/work/test$ ls
hello.c  hello.h  hello.o  libhello.a  libhello.ao  main  main.c
deroy@ubuntu:~/work/test$ rm libhello.ao
deroy@ubuntu:~/work/test$ ls
hello.c  hello.h  hello.o  libhello.a  main  main.c
deroy@ubuntu:~/work/test$ gcc -shared -fPIC hello.c -o libhello.so
deroy@ubuntu:~/work/test$ ls
hello.c  hello.h  hello.o  libhello.a  libhello.so  main  main.c
deroy@ubuntu:~/work/test$ readelf -h libhello.so
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:               ELF64
  Data:                2's complement, little endian
  Version:               1 (current)
  OS/ABI:              UNIX - System V
  ABI Version:             0
  Type:                DYN (Shared object file)
  Machine:               Advanced Micro Devices X86-64
  Version:               0x1
  Entry point address:         0x5a0
  Start of program headers:      64 (bytes into file)
  Start of section headers:      6264 (bytes into file)
  Flags:               0x0
  Size of this header:         64 (bytes)
  Size of program headers:       56 (bytes)
  Number of program headers:     7
  Size of section headers:       64 (bytes)
  Number of section headers:     29
  Section header string table index: 26

  • 生成了共享库之后,可以这样来使用共享库:
gcc -o main main.c -L . -lhello
#直接执行会报错,解决方法
#方法一:拷贝.so文件到系统共享库路径下,一般指/usr/lib或者/lib/目录
sudo cp libhello.so /usr/lib/
#方法二:在~/.bash_profile文件中,配置LD_LIBRARY_PATH变量
export LD_LIBRARY_PATH=./
deroy@ubuntu:~/work/test$ gcc -o main main.c -L . -lhello
deroy@ubuntu:~/work/test$ ls
hello.c  hello.h  hello.o  libhello.a  libhello.so  main  main.c
deroy@ubuntu:~/work/test$ ./main
./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
deroy@ubuntu:~/work/test$ ldd main
    linux-vdso.so.1 =>  (0x00007ffd467d9000)
    libhello.so => not found
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6fa83d2000)
    /lib64/ld-linux-x86-64.so.2 (0x000055e7399ee000)
deroy@ubuntu:~/work/test$ cp libhello.so /usr/lib/
cp: cannot create regular file '/usr/lib/libhello.so': Permission denied
deroy@ubuntu:~/work/test$ sudo cp libhello.so /usr/lib/
[sudo] password for deroy:
deroy@ubuntu:~/work/test$ ./main
hello world!
deroy@ubuntu:~/work/test$ sudo rm /usr/lib/libhello.so
deroy@ubuntu:~/work/test$ ./main
./main: error while loading shared libraries: libhello.so: cannot open shared object file: No such file or directory
deroy@ubuntu:~/work/test$ export LD_LIBRARY_PATH=./
deroy@ubuntu:~/work/test$ ./main
hello world!
deroy@ubuntu:~/work/test$ ldd main
    linux-vdso.so.1 =>  (0x00007ffc2f9d8000)
    libhello.so => ./libhello.so (0x00007fa4712c6000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa470ee3000)
    /lib64/ld-linux-x86-64.so.2 (0x000055d6e2f08000)
  该命令与使用静态库的命令相同,但是在共享库与静态库共存的情况下,优先使用共享库。
  共享库有时候并不不在当前的目录下,为了让gcc能够找得到共享库,有下面几种方法:
  • 拷贝.so文件到系统共享库路径下,一般指/usr/lib
  • 在~/.bash_profile文件中,配置LD_LIBRARY_PATH变量
  • 配置/etc/ld.so.conf,配置完成后调用ldconfig更新ld.so.cache
  其中,shared选项表示生成共享库格式。fPIC表示产生位置无关码(position independent code),位置无关码表示它的运行、加载与内存位置无关,可以在任何内存地址进行加载。
制作动态库
  动态库后缀: .so – libmyname.so
  制作步骤:
  •   生成与位置无关的代码(.o)
    gcc -fPIC -c *.c -Iinclude
  •   将.o打包生成.so文件
    gcc -shared *.o -o libmytest.so
  •   使用 main.c lib include
    gcc main.c -Llib -lmytest -Iinlude -o app
  应用程序不能执行, 动态链接器连接不到自己制作的库
  •   临时设置的方法:
    export LD_LIARARY_PATH=./lib
  •   永久设置的方法:
  找到动态链接库的配置文件: /etc/ld.so.conf
  在该文件中添加动态库的目录(绝对路径)
  更新: sudo ldconfig -v
关注下面的标签,发现更多相似文章