如何将我的 main.c 文件与我的库 .a 文件链接起来?

时间:2021-05-05 12:58:24

标签: c linux gcc shared-libraries static-libraries

我正在尝试制作一个属于我的静态库。假设有两个文件:stack.h 存储我想存储在 ./include 文档中的声明,stack.c 实现定义,main.c 调用文件中的函数stack.h

使用这些说明制作 stack.a 文件,我想将其存储在 ./lib 中:

>> gcc -c stack.c
>> ar -cq libstack.a stack.o
>> mv stack.h include
>> mv libstack.a lib

如果我想将 main.c 与我的 libstack.a 链接,我将如何处理 gcc?我需要把这个库放到 PATH 中吗?如果是这样,该怎么做? 如果下一步,我想做我的动态库 .so 文件,谁能给点建议?

2 个答案:

答案 0 :(得分:1)

C 库

一般来说,库是从许多库源文件创建的,或者构建为静态链接到使用它们的可执行文件的存档文件 (libmine.a),或者构建为动态链接的共享对象文件 (libmine.so)到使用它们的可执行文件中。要链接这些类型的库,请使用 gcc 命令行选项 -L 作为库文件的路径,并使用 -l 链接库(.so 或 .a) :

    -L{path to file containing library} -l${library name}

例如,如果我在 /home/newhall/lib/ 中有一个名为 libmine.so 的库,那么我会执行以下操作将其链接到我的程序中:

$ gcc -o myprog myprog.c  -L/home/newhall/lib -lmine

您可能还需要指定并包含路径,以便编译器可以找到库头文件:-I /home/newhall/include

如果您创建了自己的共享对象文件并且没有将它们安装在 /usr/lib 中,那么您需要设置 LD_LIBRARY_PATH 环境变量,以便运行时链接程序可以在运行时找到它们并加载它们。

例如,如果我将 .so 文件放在 lib 目录中名为 home 的目录中,我会将 LD_LIBRARY_PATH 环境设置为以下内容:

# 如果运行 bash:

>> export LD_LIBRARY_PATH=/home/newhall/lib:$LD_LIBRARY_PATH

# 如果运行 tcsh:

>> setenv LD_LIBRARY_PATH /home/newhall/lib:$LD_LIBRARY_PATH

使用和链接库代码

要使用未通过以下方式自动链接到您的程序的库 编译器,你需要

    1. 在您的 C 源文件中包含库的头文件(以下示例中的 test.c
    1. 告诉编译器将库 .o 文件中的代码链接到您的可执行文件中:

    步骤 1:在程序中添加包含行(#include "somelib.h") 源文件(例如 test.c)。

    第 2 步:将程序的 .c 文件与库对象文件链接 (即,将 somelib.o 文件指定为 gcc 的命令行参数):

    >> gcc  -o myprog test.c somelib.o
    

    生成的可执行文件 (myprog) 将包含所有机器码 test.c 中定义的函数加上调用的任何 mylib 库函数。

创建和使用您自己的库代码

要创建代码库,您需要执行以下操作:

(1) 为你的库创建一个接口:mylib.h

(2) 为你的库创建一个实现:mylib.c

(3) 创建一个可以与使用您的库的程序链接的库对象文件 (.o)

  • 3a。或从许多 .o 文件创建一个共享对象文件 (.so),这些文件可以与使用您的库的程序动态链接

  • 3b。或从许多 .o 文件创建一个存档文件 (.a),这些文件可以与使用您的库的程序静态链接

(4) 在其他 C 代码中使用库: (a) #include "mylib.h" (b) 将库代码中的链接到 a.out 文件

(5) 设置 LD_LIBRARY_PATH 环境变量,用于在运行时查找非标准位置的共享对象

详情:

(1) 接口:库的头文件应包含库导出的所有内容的定义:

  • 带有库函数用户注释的函数原型

  • 库导出的类型和全局变量的定义

你应该在头文件的内容周围有“样板”代码(#ifndef ... #endif),以确保预处理器只包含一次 mylib.h 文件。

示例 .h 文件可能如下所示:

#ifndef MYLIB_H_                // _MYLIB_H_ is not allowed.
#define MYLIB_H_

    // a constant definition exported by library:
    #define MAX_FOO  20

    // a type definition exported by library:
        struct foo_struct {  
        int x;
        float y;
    };
    typedef struct foo_struct foo_struct;

    // a global variable exported by library
    // "extern" means that this is not a variable declaration, it 
    // just defines that a variable named total_foo of type int
    // exits and you can use it (its declaration is in some library source file)
    extern int total_foo;   

    // a function prototype for a function exported by library:
    extern int foo(float y, float z);   // a very bad function name

#endif

(2) 实现:创建一个 mylib.c 文件,其中 #includes "mylib.h" 并包含库中每个函数的实现。

    #include "mylib.h"

    ...
    int total_foo;

    int foo(float y, float z) { 
    ...
    } 

(3) 创建一个 LIBRARY OBJECT FILE,它可以链接到使用你的库的其他程序中(使用 gcc 的 -c 选项告诉它只是创建一个目标文件(一个 .o 文件)而不是一个可执行文件:

>> gcc -o mylib.o -c mylib.c

然后您可以将 mylib.o 文件用作“库文件”并将其静态链接到使用它的其他程序,或者...

  • (3a) 或者,您可以从一个或多个 .o 文件创建一个共享对象文件,这些文件可以链接到使用您的库的其他程序中 共享对象文件是其代码已加载的动态链接库的 Unix 名称在运行时进入 a.out 文件。要创建 .so 文件,请使用 gcc 的 -shared 标志。以下是示例构建的样子:
    >> gcc -shared -o libmylib.so  mylib.o blah.o grr.o  -lm
    
  • (3b) 您还可以从一个或多个 .o 文件构建存档文件(静态链接库,libmylib.a)。如果链接静态库,则其代码会在运行时复制到 a.out 文件中。 有关如何构建 .a 和 .so 文件的更多信息,请参阅 gcc 文档。

(4) 在其他程序中使用该库:

  • 步骤 1:在所有使用库定义(例如 test.c)的程序源文件中添加包含行(#include "mylib.h")。

  • 第 2 步:将程序的 .c 文件与库对象文件链接 (即指定 mylib.o 文件作为 gcc 的命令行参数):

           gcc  test.c mylib.o
    
      OR to link in libmylib.so (or libmylib.a):
    
           gcc  test.c -lmylib
    
      OR to link with a library not in the standard path:
    
           gcc  test.c -L/home/newhall/lib -lmylib
    
      The resulting a.out out will contain machine code for all the functions 
      defined in test.c plus any mylib library functions that are called by 
      the test.c code. 
    

(5) 运行与共享目标文件链接的可执行文件:

如果共享对象文件不在/usr/lib中,那么你需要设置你的 LD_LIBRARY_PATH 环境变量,以便运行时链接器可以找到 并在运行时将您的 .so 文件加载到可执行文件中:

在 bash 中:

>> export LD_LIBRARY_PATH=/home/newhall/lib:$LD_LIBRARY_PATH

在 tcsh 中:

>> setenv LD_LIBRARY_PATH /home/newhall/lib:$LD_LIBRARY_PATH

答案 1 :(得分:0)

还有一个有用的链接:demo for making libraries