【问题标题】:Include an external library in C在 C 中包含一个外部库
【发布时间】:2012-07-28 05:13:25
【问题描述】:

我正在尝试将 C 库用于哈佛的开放课件课程。可以在here 找到教师关于设置外部库的说明。

当我尝试在我的 ubuntu 机器上使用这个库时,我正在遵循特定于 ubuntu 的说明。我按照页面上的说明进行设置,但是当我使用 cs50 库函数运行一个简单的helloWorld.c 程序时,gcc 不想一起玩。

例子:

helloWorld.c

#include <stdio.h>
#include <cs50.h>

int
main(void){
        printf("What do you want to say to the world?\n");
        string message = GetString();
        printf("%s!\n\n", message);
}

$ gcc helloWorld.c

/tmp/ccYilBgA.o: In function `main':
helloWorld.c:(.text+0x16): undefined reference to `GetString'
collect2: ld returned 1 exit status

我按照说明中的说明按照信函的说明进行操作,但它们对我不起作用。我正在运行 ubuntu 12.04。如果我能进一步澄清我的问题,请告诉我。

【问题讨论】:

  • 头文件包含只是标志着函数的原型。因此,您的文件可以正常编译,但存在链接错误。您是否按照建议安装了库?如果是这样,您能否检查这些库是否已正确安装并且路径变量是否已正确设置,以便 gcc 可以使用该路径找到这些库?
  • gcc helloWorld.c -lcs50 工作吗?
  • 是的,没有意识到我必须在 cmd 行显式链接到 lib。谢谢大家。
  • 它怎么知道你想链接到那个库?
  • 我在想 #include &lt;cs50.h&gt; 会像 #include &lt;stdio.h&gt; 一样工作。

标签: c cs50


【解决方案1】:

首先,作为初学者,您应该始终要求 GCC 编译时启用所有警告和调试信息,即gcc -Wall -g。但有时阅读How to invoke gcc。使用好的source code editor(如GNU emacsvimgedit等)来编辑你的C源代码,但能够在命令行上编译你的程序(所以不要总是使用复杂的IDE 向您隐藏重要编译细节)。

那么您可能缺少一些哈佛特定的库,一些选项,如 -L 后跟库目录,然后将 -l 粘在库名称上。所以你可能需要gcc -Wall -g -lcs50(用适当的名称替换cs50),你可能需要一些-Lsome-dir

请注意,gcc 的程序参数的顺序很重要。作为一般规则,如果a 依赖于b,则应将a 放在b 之前;更具体地说,我建议

  1. gcc 程序名开头;如果需要,添加 C 标准级别,例如 -std=c99
  2. 添加编译器警告、调试(或优化)选项,例如-Wall -g(您甚至可能想要添加-Wextra 以获得更多警告)。
  3. 放置预处理器的定义和包含目录,例如-DONE=1-Imy-include-dir/
  4. 把你的C源文件hello.c
  5. 放置您要链接的任何目标文件,即bar.o
  6. 如果相关,请将库目录-Lmy-lib-dir/
  7. Pur 库名称 -laa-lbb(当 libaa.so 依赖于 libbb.so 时,按此顺序)
  8. -o your-program-name 结尾以给出生成的二进制文件的名称。不要使用默认名称a.out

目录提供选项-I(用于预处理器包含)和-L 用于库可以多次提供,顺序很重要(搜索顺序)。

很快你就会想要使用build automation 工具,比如GNU make(可能在Linux 上使用help of remake

也向use the debugger gdb学习。

养成始终向编译器请求警告的习惯,并始终改进您的程序,直到您没有收到任何警告:编译器是您的朋友,它正在帮助您!

另请阅读How to debug small programs 和著名的SICP(它教授了非常重要的概念;您可能想在阅读时使用use guile on Linux,请参阅http://norvig.com/21-days.html 了解更多信息)。还要注意valgrind 等工具

玩得开心。

【讨论】:

    【解决方案2】:

    我参加了这门课程,有时我需要在旅行或通勤时离线练习。在 Windows 下使用 MinGW 和 Notepad++ 作为 IDE(因为我喜欢它并且经常在编写 python 时使用它)我终于找到了一个解决方案并有时间写下来。

    从头开始。 gcc C编译器设置步骤,如果已经设置请跳至5

    1. Download Git 并安装。它包括 Git Bash,它是 MINGW64 linux 终端。我更喜欢使用 Git,因为我需要在我的 Windows 上使用 sed、awk、pull、push 等 linux 工具,并且可以替换 Guthub 的终端。
    2. 安装 Git 后,请确保已安装 gcc 包。可以参考我的配置...
    3. 确保您的编译器工作正常。抛出这个简单的代码,

      • 将其保存在您的工作目录中Documents/Harvard_CS50/Week2/ 你好.c
      #include <stdio.h>
      
      int main(void)
      {
       printf("Hello StackOverflow\n");
      }
      
      • 启动 Git Bash -> 导航到工作目录

      cd 文档/Harvard_CS50/Week2/

      • 在 bash 终端中编译

      gcc helloworld.c -o helloworld.exe

      • 使用 bash 终端执行它

      ./helloworld.exe

      你好 StackOverflow

      1. 如果您看到 Hello StackOverflow,则说明您的编译器工作正常,您可以编写 C 代码。

    现在最重要的是,在本地安装 CS50 库并离线使用它。这应该适用于本课程后面介绍的任何其他库。

    1. https://github.com/cs50/libcs50/tree/develop/src下载最新的源代码文件cs50.c和头文件cs50.h并保存在Documents/Harvard_CS50/src

    2. 导航到 src 目录并列出文件以确保您在正确的位置使用

      ls

      cs50.c cs50.h

    3. 酷,我们来了。现在我们需要为库编译目标文件使用

      gcc -c -ggdb -std=c99 cs50.c -o cs50.o

    4. 现在使用生成的 cs50.o 目标文件,我们可以创建我们的 cs50 库存档文件。

      ar rcs libcs​​50.a cs50.o

    5. 完成所有这些步骤后,我们在原始文件中添加了 2 个附加文件。我们只对其中 2 个感兴趣 cs50.h libcs​​50.a

      ls

      cs50.c cs50.h cs50.o libcs​​50.a

    6. 将库和头文件复制到它们的目标位置。我的 MinGW 安装在 C:\ 所以我把它们复制到那里

      cs50.h --> C:\MinGW\include

      libcs​​50.a --> C:\MinGW\lib

    测试 cs50 库

    为了确保我们的库正常工作,我们可以在讲座中抛出一个示例脚本,看看是否可以使用 get_string() 方法的 cs50.h 头文件编译它。

    #include <stdio.h>
    #include <cs50.h>
    
    int main(void) 
    {
        printf("Please input a string to count how long it is: ");
        string s = get_string();
        int n = 0;
        while (s[n] != '\0')
            {
                n++;
            }
        printf("Your string is %i chars long\n", n); 
    }
    
    1. 使用 gcc 和 cs50 库编译 cs50 代码。我想明确并使用:

      gcc -ggdb -std=c99 -Wall -Werror test.c -lcs50 -o test.exe

      但你可以简单地指出源、输出文件名和cs50库

      gcc test.c -o test.exe -lcs50

    到这里,程序是用header编译的,方法可以在里面使用。

    If you want Notepad++ as an IDE you can follow this tip to set it up with gcc as a compiler and run your code from there。 只需确保您的 nppexec 脚本包含 cs50 库

    npp_save
    gcc -ggdb -std=c99 -Wall -Werror "$(FULL_CURRENT_PATH)" -lcs50 -o "$(CURRENT_DIRECTORY)\$(NAME_PART).exe"
    cmd /c "$(CURRENT_DIRECTORY)\$(NAME_PART).exe"
    

    【讨论】:

    • Windows 用户的完美答案!感谢您对图像的详尽解释。我想为第 10 步添加一点,您要查找的文件夹位置应包含 stdio.h 文件。对我来说,它是:C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\x86_64-w64-mingw32,其中包含我需要的 includelib 文件夹。另外,感谢 faizan-rizvi,他在回答中提供了进一步的线索(选项 2,步骤 2)。
    【解决方案3】:

    您需要在编译期间链接库。如果您在 Ubuntu 上,该库应以 .a 或 .so 结尾。要链接到库:

    gcc -o myProgram myProgram.c -l(library name goes here but no parentheses)
    

    【讨论】:

      【解决方案4】:

      你必须链接库,GCC 怎么会知道你想使用什么库?

      gcc helloWorld.c -lcs50
      

      【讨论】:

        【解决方案5】:
        1. http://mirror.cs50.net/library50/c/library50-c-5.zip下载cs50
        2. 提取它。 (你会得到两个文件 cs50.c 和 cs50.h)
        3. 现在将这两个文件复制到您的默认库文件夹中。 (包括您的 stdio.h 文件)
        4. 现在在编写程序时使用:#include
        5. 您还可以将文件复制到包含 helloWorld.c 文件的文件夹中。
        6. 你必须使用:#include "cs50.c"。

        OR =============================================== =======================>

        1. 在文本编辑器中打开 cs50.c 和 cs50.h 文件。
        2. 在 cs50.h 中,在 #include 正下方添加 #include 和 #include 都在新行上。
        3. 现在打开 cs50.c 文件,复制所有内容(来自:/**从标准输入读取一行文本并返回等效的 {从第 47 行到最后一个})并将其粘贴到 cs50.h 中 #endif 上方并保存文件。
        4. 现在您可以将文件 cs50.h 复制到默认库文件夹或当前工作文件夹。
        5. 如果您将文件复制到默认文件夹,则使用:#include ,如果您将文件复制到当前工作文件夹,则使用:#include "cs50.h"。

        如果您需要帮助,可以通过 faizan4427@gmail.com 向我提问,如果可行,请投票。

        万事如意!!!

        【讨论】:

          【解决方案6】:

          研究来源:

          • 以 Basile Starynkevitch 和 Gunay Anach 给出的上述答案为基础
          • 结合youtube上一些视频的说明12

          方法:

          • 涵盖最少要做的事情,并分别分享“规范”
          • 避免对系统上的其他任何地方进行任何修改
          • 包括所用命令的基本分类
          • 不包括所有细节,仅涵盖任务绝对要求或有效传达指令的要求。将其他平凡的细节留给读者
          • 假设编译器、环境变量等其他内容已经设置好,并且熟悉 shell 的文件导航命令

          我的环境:

          • 编译器:gcc 通过 msys2
          • 外壳:bash 通过 msys2
          • IDE:这里没关系

          计划:

          1. 获取源文件
          2. 构建所需文件:*.o(对象)和*.a(存档)
          3. 告诉编译器使用它

          行动:

          1. 假设,当前目录 = "desktop/cs50"
            它包含所有 *.c 文件,例如我将为作业/问题集/练习等创建的 test-file.c。

          2. 获取*.h*.c 文件
            在这种特殊情况下的来源:https://github.com/cs50/libcs50/tree/main/src

            1. 单独检查每个文件
            2. 复制它的所有内容
              假设使用单个文件的"Copy raw contents" icon
            3. 在电脑本地创建对应文件
              在一个单独的文件夹中执行它只是为了保持干净,比如说在“desktop/cs50/src”又名./src
          3. 将当前目录更改为“desktop/cs50/src”后,在终端中使用构建所需的文件:

            1. gcc -c cs50.c 使用“gcc”从“cs50.c”创建“cs50.o”对象文件
            2. ar cr libcs50.a cs50.o 创建“libcs​​50.a”存档文件,其中将包含“cs50.o”目标文件
            • 这里,“libcs​​50”=“lib”前缀+“cs50”名称(与头文件名称相同)
            • 这是规范/标准方式,其中前缀“lib”对于后续步骤也很重要
            • 但是,前缀可以跳过,并且名称也不是必须与头文件的名称匹配。不过,不建议跳过前缀。而且我不能确定名称部分
          4. 为了告诉编译器能够使用这个基础设施,在转到父目录(即“desktop/cs50”)后,命令将采用以下语法:

            • gcc test-file.c -Isrc -Lsrc -lcs50 如果您在上面的步骤 2.2 中使用了“lib”前缀
            • 这里,-I 标志用于指定 test_file.c 中包含的 *.h 头文件的目录
            • -L 标志用于指定要用于-l 的目录
            • -l*.a 文件的名称。这里前面讲了“lib”前缀,没有提到“.a”扩展名
            • 这些标志的顺序很重要,在“test-file.c”之后保留-I -L -l 标志

          还有一些注意事项:

          • 不要忘记使用额外的通用标志(如上面针对错误等建议的标志)
          • 如果你跳过了“lib”前缀,那么你就不能使用-L -l标志
            因此,命令的语法将变为:gcc test-file.c -Isrc src/libcs50.a
          • 假设我在“desktop/cs50/psets”中创建了我的test-file.c 文件,因此,它可以通过两种值得注意的方式进行处理(当前目录 =“desktop/cs50/”):
            • cd psets 然后在-I -L 中相应地改变相对地址,所以结果:
              gcc test-file.c -I../src -L../src -lcs50
            • 保持当前目录不变,但相应地改变文件的相对地址,所以结果:
              gcc psests/test-file.c -Isrc -Lsrc -lcs50
            • 或使用绝对地址?
          • 可以看出这会变得很长,这就是构建自动化工具(例如 make)的时候(尽管我正在使用 shell 脚本来完成这个任务?)

          【讨论】:

            猜你喜欢
            • 2020-06-22
            • 1970-01-01
            • 1970-01-01
            • 2021-02-08
            • 2011-12-20
            • 2018-04-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多