<commit_before>---
layout:     post
title:      "关于头文件"
subtitle:   " \"注意有三个例外\""
date:       2017-10-19 12:00:00
author:     "Lynn"
header-img: "img/home-bg-o.jpg"
catalog: true
tags:
    - 渣渣程序员
    - C++
---


> “渣渣程序员. ”



 程序编译一般需要经预处理、编译、汇编和链接几个步骤。在实际应用中，有些公共代码需要反复使用，就把这些代码编译成为“库”文件。在链接步骤中，连接器将从库文件取得所需的代码，复制到生成的可执行文件中，这种库称为静态（链接）库，其特点是可执行文件中包含了库代码的一份完整拷贝，缺点是被多次使用就会多份冗余拷贝。还有一种库，就是程序在开始运行后调用库函数时才被载入，这种库独立于现有的程序，其本身不可执行，但包含着程序需要调用的一些函数，这种库称为动态（链接）库（Dynamic Link Library）。
 ![](http://ww1.sinaimg.cn/large/664c3452ly1fkwm5p1fshj20fe07bq3s.jpg)

       在widows平台下，静态链接库是.lib文件，动态库文件是.dll文件。在linux平台下，静态链接库是.a文件，动态链接库是.so文件。这里主要讲在linux平台下的动态库和静态库的生成以及链接。本文主要参考【1】【2】【3】【4】
       


## 一、库的基本知识

 首先说明要对库有一个比较直观的理解。库是写好的现有的，成熟的，可以复用的代码。现实中每个程序都依赖很多基础的底层库，不可能每个人的代码都从零开始，因此库的存在意义非同寻常。本质上说来库是一种可执行代码的二进制形式（注，其本身不可执行），可以被操作系统载入内存执行。
       静态链接库，之所以称为“静态库”，是因为在链接阶段，会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中，因此对应的链接方式为静态链接。其实一个静态链接库可以简单看成一组目标文件(.o/.obj文件)的集合，即很多目标文件经过压缩打包后形成的一个文件。静态库特点总结：
              1. 静态库对函数库的链接是放在编译时期完成
              2. 程序在运行时对函数库再唔瓜葛，一直方便。
              3. 浪费空间和资源，因为所有相关的目标文件和牵涉到的函数库被链接合成一个可执行文件。
       linux下使用ar工具（windows下用lib.exe）（具体的用法参考【5】），可以将目标文件压缩到一起，并且对其进行编号和索引，一便于查找和索引。一般创建静态链接库的步骤如下：
       ![](http://ww1.sinaimg.cn/large/664c3452ly1fkwm6v2278j20dg08st9g.jpg)

        静态链接库的命名规则，库的名称和库文件名称不同，有联系，假定库名称为"my_library_name"，那么起库文件名为"lib[my_library_name].a"(方括号是为了区分，实际上没有)
        动态链接库，在程序编译是并不会被连接到目标代码中，而是在程序运行时才被载入。不同的应用程序如果调用相同的库，那么在内存里只需要有一份该共享库的实例，规避了空间浪费问题。动态库的一些总结：
           1. 动态库把对一些库函数的链接载入推迟到程序运行时期
           2. 可以实现进程之间的资源共享，（动态库也成为共享库）
           3. 将一些程序升级变得简单
           4. 设置可以真正做到链接载入完全由程序员在程序代码中控制（显式调用）
        Linux下gcc编译的执行文件默认是ELF格式，不需要初始化入口，亦不需要函数做特别的声明，编写比较方便。与windows系统下的格式不同。与创建静态库不同的是，不需要打包工具，直接使用编译器即可创建动态库。
        ![](http://ww1.sinaimg.cn/large/664c3452ly1fkwm80659dj20cr0b8abe.jpg)

        动态链接库的命名规则，与静态链接库的方式相同，不过其后缀名为.so，命名形式为"lib[my_library_name].so"   。但是在实际使用过程中libxxx.so 大多数情况只是一个链接，它链接到一个包含版本信息的库文件 libxxxx.so.xx，如下图。当然自己可以使用 ln 命令，制作链接 ln -s libxxxx.so.xx libxxxx.so。

---

## 二、库的编译和链接

库的编译和链接
        下面使用一个例子来说明链接库是如何生成与链接的。这个例子的源代码参考【4】。这里有五个文件，头文件“SoDemoTest.h”，三个cpp文件“one.cpp”、"two.cpp"、"three.cpp"，main函数实现文件“main.cpp”。
[cpp] view plain copy

'\#ifndef _SO_DEMO_TEST_HEADER_  
\#define _SO_DEMO_TEST_HEADER_  
\#include <iostream\>  
using namespace std;  
void one();  
void two();  
void three();  
endif  
/* one.cpp */  
include "SoDemoTest.h"  
void one(){  
    cout << "call one() function" << endl;  
}  
/* two.cpp */  
\#include "SoDemoTest.h"  
void two(){  
    cout << "call two() function" << endl;  
}  
/* three.cpp */  
\#include "SoDemoTest.h"  
void three(){  
    cout << "call three() function" << endl;  
}  
/* main.cpp */  
\#include "SoDemoTest.h"  
int main(){  
    one();  
    two();  
    three();  
    return 0;  
}  
'

      gcc/g++的编译参数，这里只介绍 -L 、-l、-include、-I、-shared、-fPIC
      -L ：表示要链接的库所在的目录。-L.  表示要链接的库在当前目录， -L/usr/lib 表示要连接的库在/usr/lib下。目录在/usr/lib时，系统会自动搜索这个目录，可以不用指明。
     -l (L的小写)：表示需要链接库的名称，注意不是库文件名称，比如库文件为 libtest.so，那么库名称为test
     -include ：包含头文件，这个很少用，因为一般情况下在源码中，都有指定头文件。
      -I (i 的大写)：指定头文件的所在的目录，可以使用相对路径。
     -shared ：指定生成动态链接库
     -fPIC：  表示编译为位置独立的代码，不用此选项的话编译后的代码是位置相关的所以动态载入时事通过代码拷贝的方式来满足不同进程的需要，而不能达到真正代码共享的目的。

      生成链接库
      第1步，生成目标文件：g++ -c xxx.cpp

       第2步，创建静态链接库:  ar  cqs  libxxxx.a  xx1.o xx2.o xx3.o (参数选项请看【5】)

        第3步，程序中使用静态链接库

        第4步，创建动态链接库 g++ -fPIC -shared -o libxxx.so xx1.cpp xx2.cpp xx3.cpp

        第5步，动态链接库使用
<commit_msg>20171027<commit_after>---
layout:     post
title:      "动态静态库的编译与链接"
subtitle:   " \"终于把day1搞定了\""
date:       2017-10-27 12:00:00
author:     "Lynn"
header-img: "img/home-bg-o.jpg"
catalog: true
tags:
    - 渣渣程序员
    - C++
---


> “渣渣程序员. ”



 程序编译一般需要经预处理、编译、汇编和链接几个步骤。在实际应用中，有些公共代码需要反复使用，就把这些代码编译成为“库”文件。在链接步骤中，连接器将从库文件取得所需的代码，复制到生成的可执行文件中，这种库称为静态（链接）库，其特点是可执行文件中包含了库代码的一份完整拷贝，缺点是被多次使用就会多份冗余拷贝。还有一种库，就是程序在开始运行后调用库函数时才被载入，这种库独立于现有的程序，其本身不可执行，但包含着程序需要调用的一些函数，这种库称为动态（链接）库（Dynamic Link Library）。
 ![](http://ww1.sinaimg.cn/large/664c3452ly1fkwm5p1fshj20fe07bq3s.jpg)

       在widows平台下，静态链接库是.lib文件，动态库文件是.dll文件。在linux平台下，静态链接库是.a文件，动态链接库是.so文件。这里主要讲在linux平台下的动态库和静态库的生成以及链接。本文主要参考【1】【2】【3】【4】
       


## 一、库的基本知识

 首先说明要对库有一个比较直观的理解。库是写好的现有的，成熟的，可以复用的代码。现实中每个程序都依赖很多基础的底层库，不可能每个人的代码都从零开始，因此库的存在意义非同寻常。本质上说来库是一种可执行代码的二进制形式（注，其本身不可执行），可以被操作系统载入内存执行。
       静态链接库，之所以称为“静态库”，是因为在链接阶段，会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中，因此对应的链接方式为静态链接。其实一个静态链接库可以简单看成一组目标文件(.o/.obj文件)的集合，即很多目标文件经过压缩打包后形成的一个文件。静态库特点总结：
              1. 静态库对函数库的链接是放在编译时期完成
              2. 程序在运行时对函数库再唔瓜葛，一直方便。
              3. 浪费空间和资源，因为所有相关的目标文件和牵涉到的函数库被链接合成一个可执行文件。
       linux下使用ar工具（windows下用lib.exe）（具体的用法参考【5】），可以将目标文件压缩到一起，并且对其进行编号和索引，一便于查找和索引。一般创建静态链接库的步骤如下：
       ![](http://ww1.sinaimg.cn/large/664c3452ly1fkwm6v2278j20dg08st9g.jpg)

        静态链接库的命名规则，库的名称和库文件名称不同，有联系，假定库名称为"my_library_name"，那么起库文件名为"lib[my_library_name].a"(方括号是为了区分，实际上没有)
        动态链接库，在程序编译是并不会被连接到目标代码中，而是在程序运行时才被载入。不同的应用程序如果调用相同的库，那么在内存里只需要有一份该共享库的实例，规避了空间浪费问题。动态库的一些总结：
           1. 动态库把对一些库函数的链接载入推迟到程序运行时期
           2. 可以实现进程之间的资源共享，（动态库也成为共享库）
           3. 将一些程序升级变得简单
           4. 设置可以真正做到链接载入完全由程序员在程序代码中控制（显式调用）
        Linux下gcc编译的执行文件默认是ELF格式，不需要初始化入口，亦不需要函数做特别的声明，编写比较方便。与windows系统下的格式不同。与创建静态库不同的是，不需要打包工具，直接使用编译器即可创建动态库。
        ![](http://ww1.sinaimg.cn/large/664c3452ly1fkwm80659dj20cr0b8abe.jpg)

        动态链接库的命名规则，与静态链接库的方式相同，不过其后缀名为.so，命名形式为"lib[my_library_name].so"   。但是在实际使用过程中libxxx.so 大多数情况只是一个链接，它链接到一个包含版本信息的库文件 libxxxx.so.xx，如下图。当然自己可以使用 ln 命令，制作链接 ln -s libxxxx.so.xx libxxxx.so。

---

## 二、库的编译和链接

库的编译和链接
        下面使用一个例子来说明链接库是如何生成与链接的。这个例子的源代码参考【4】。这里有五个文件，头文件“SoDemoTest.h”，三个cpp文件“one.cpp”、"two.cpp"、"three.cpp"，main函数实现文件“main.cpp”。
[cpp] view plain copy

'\#ifndef _SO_DEMO_TEST_HEADER_  
\#define _SO_DEMO_TEST_HEADER_  
\#include <iostream\>  
using namespace std;  
void one();  
void two();  
void three();  
endif  
/* one.cpp */  
include "SoDemoTest.h"  
void one(){  
    cout << "call one() function" << endl;  
}  
/* two.cpp */  
\#include "SoDemoTest.h"  
void two(){  
    cout << "call two() function" << endl;  
}  
/* three.cpp */  
\#include "SoDemoTest.h"  
void three(){  
    cout << "call three() function" << endl;  
}  
/* main.cpp */  
\#include "SoDemoTest.h"  
int main(){  
    one();  
    two();  
    three();  
    return 0;  
}  
'

      gcc/g++的编译参数，这里只介绍 -L 、-l、-include、-I、-shared、-fPIC
      -L ：表示要链接的库所在的目录。-L.  表示要链接的库在当前目录， -L/usr/lib 表示要连接的库在/usr/lib下。目录在/usr/lib时，系统会自动搜索这个目录，可以不用指明。
     -l (L的小写)：表示需要链接库的名称，注意不是库文件名称，比如库文件为 libtest.so，那么库名称为test
     -include ：包含头文件，这个很少用，因为一般情况下在源码中，都有指定头文件。
      -I (i 的大写)：指定头文件的所在的目录，可以使用相对路径。
     -shared ：指定生成动态链接库
     -fPIC：  表示编译为位置独立的代码，不用此选项的话编译后的代码是位置相关的所以动态载入时事通过代码拷贝的方式来满足不同进程的需要，而不能达到真正代码共享的目的。

      生成链接库
      第1步，生成目标文件：g++ -c xxx.cpp

       第2步，创建静态链接库:  ar  cqs  libxxxx.a  xx1.o xx2.o xx3.o (参数选项请看【5】)

        第3步，程序中使用静态链接库

        第4步，创建动态链接库 g++ -fPIC -shared -o libxxx.so xx1.cpp xx2.cpp xx3.cpp

        第5步，动态链接库使用

{'fraction_non_alphanumeric': 0.13412901392441035, 'fraction_numerical': 0.027706734867860187, 'mean_word_length': 3.8444597384721266, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7658206', 'n_tokens_mistral': 5003, 'n_tokens_neox': 5641, 'n_words': 328}