7

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

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

例子:

你好世界.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。如果我能进一步澄清我的问题,请告诉我。

4

6 回答 6

34

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

然后你可能会错过一些哈佛特定的图书馆,一些选项,比如-L后跟图书馆目录,然后-l粘在图书馆名称上。所以您可能需要gcc -Wall -g -lcs50(用cs50适当的名称替换)并且您可能需要一些-L目录

请注意,程序参数的顺序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库可以多次提供,顺序很重要(搜索顺序)。

很快你就会想要使用像GNU这样的构建自动化工具(也许在 Linux的帮助下)makeremake

还要学习使用调试器gdb

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

另请阅读如何调试小程序和著名的SICP(它教授了非常重要的概念;您可能希望在阅读时在 Linux上使用,请参阅guilehttp://norvig.com/21-days.html了解更多信息)。还要注意像valgrind这样的工具

玩得开心。

于 2012-07-28T05:19:59.510 回答
5

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

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

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

    • 通过将其保存在您的工作目录Documents/Harvard_CS50/Week2/ hello.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/libcs ​​50/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

在这里,程序是使用头文件编译的,并且可以在其中使用方法。

如果您希望 Notepad++ 作为 IDE,您可以按照此提示将其设置为 gcc 作为编译器并从那里运行您的代码。只需确保您的 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"

在 Notepad++ 中运行 CS50 代码

于 2017-08-18T13:05:21.613 回答
3

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

gcc -o myProgram myProgram.c -l(library name goes here but no parentheses)
于 2012-07-28T05:19:03.300 回答
2

您必须链接到库,GCC 怎么会知道您要使用哪个库?

gcc helloWorld.c -lcs50
于 2012-07-28T05:20:32.130 回答
2
  1. 从http://mirror.cs50.net/library50/c/library50-c-5.zip下载 cs50
  2. 提取它。(您将获得两个文件 cs50.c 和 cs50.h)
  3. 现在将这两个文件复制到您的默认库文件夹。(其中包括您的 stdio.h 文件)
  4. 现在在编写程序时使用:#include < cs50.c >
  5. 您还可以将文件复制到包含 helloWorld.c 文件的文件夹中。
  6. 你必须使用:#include "cs50.c"。

或 ================================================== =====================>

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

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

祝一切顺利!!!

于 2016-03-26T13:49:02.403 回答
0

研究来源:

  • 基于 Basile Starynkevitch 和 Gunay Anach 给出的上述答案
  • 结合 youtube 上一些视频的说明1 2

方法:

  • 涵盖最少要做的事情,并分别分享“规范”
  • 避免对系统上其他任何地方进行任何修改
  • 包括使用的命令的基本分解
  • 不包括所有细节,仅涵盖任务绝对要求或有效传达指令的要求。将其他平凡的细节留给读者
  • 假设编译器、环境变量等其他东西已经设置好,并且熟悉 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/libcs​​50/tree/main/src

    1. 分别浏览每个文件
    2. 复制它的所有内容
      使用单个文件的“复制原始内容”图标说
    3. 在计算机本地创建相应的文件在一个
      单独的文件夹中执行它只是为了保持干净,比如说在“desktop/cs50/src”aka./src
  3. Build the required files using in the terminal after changing your current directory to "desktop/cs50/src" :

    1. gcc -c cs50.c to create the "cs50.o" object file from "cs50.c" using "gcc"
    2. ar cr libcs50.a cs50.o to create "libcs50.a" archive file which'll be containing "cs50.o" object file
    • Here, "libcs50" = "lib" prefix + "cs50" name (same as the header file's name)
    • This is the norm/standard way where the prefix "lib" is significant as well for a later step
    • However, prefix can be skipped, and it's not compulsory for name to match the header file's name either. Though, Skipping prefix is not recommended. And I can't say for sure about the name part
  4. 为了告诉编译器能够使用这个基础结构,在转到父目录(即“desktop/cs50”)后,命令将采用以下语法:

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

还有一些注意事项:

  • 不要忘记使用额外的通用标志(如上面建议的错误等)
  • 如果你跳过了“lib”前缀,那么你就不能使用-L -l标志
    ,所以命令的语法将变为:gcc test-file.c -Isrc src/libcs50.a
  • 假设我在“desktop/cs50/psets”中创建了我的test-file.c文件,因此,可以通过 2 种值得注意的方式处理它(当前目录 =“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 脚本来完成)
于 2021-12-09T21:12:48.987 回答