编译过程

发布于 2024-07-12 09:35:48 字数 1242 浏览 11 评论 0原文

谁能解释一下编译是如何工作的?

我似乎无法弄清楚编译是如何工作的..

更具体地说,这是一个例子..我正在尝试在 MSVC++ 6 中编写一些代码来加载 Lua 状态..

我已经:

  • 设置附加目录对于库并将文件包含到正确的目录中,
  • 使用 extern "C" (因为 Lua 仅是 C 语言,所以我听说)
  • 包含正确的头文件

但我仍然在 MSVC++6 中遇到一些关于未解析的外部符号的错误(对于我使用的 Lua 函数)。

尽管我很想知道如何解决这个问题并继续前进,但我认为如果我了解所涉及的底层流程对我来说会更好,所以有人可以为此写一个很好的解释吗? 我想知道的是这个过程..它可能看起来像这样:

第 1 步:

  • 输入:源代码
  • 过程:解析(也许在此处添加更多详细信息)
  • 输出:此处输出的任何内容..

第 2 步:

  • 输入:无论第 1 步输出什么,加上可能还需要其他任何内容(库?DLL?.so?.lib?)
  • 进程:对输入执行的任何
  • 操作 输出:输出的任何内容

等等..

谢谢..

也许这会解释什么是符号,到底什么是“链接”,什么是“对象”代码或其他什么..

谢谢..抱歉我是个菜鸟..PS

这不一定是特定于语言的..但请随意表达使用您最熟悉的语言.. :)

编辑:所以无论如何,我能够解决错误,事实证明我必须手动将 .lib 文件添加到项目; 简单地在 IDE 设置或项目设置中指定库目录(.lib 所在的位置)是行不通的。

但是,下面的答案在一定程度上帮助我更好地理解了该过程。 非常感谢!...如果有人仍然想写一份完整的指南,请这样做..:)

编辑:仅供参考,我找到了一位作者(Mike Diehl)的两篇文章来解释这一点很好.. :) 检查编译过程:第 1 部分 检查编译过程:第 2 部分

Can anyone explain how compilation works?

I can't seem to figure out how compilation works..

To be more specific, here's an example.. I'm trying to write some code in MSVC++ 6 to load a Lua state..

I've already:

  • set the additional directories for the library and include files to the right directories
  • used extern "C" (because Lua is C only or so I hear)
  • include'd the right header files

But i'm still getting some errors in MSVC++6 about unresolved external symbols (for the Lua functions that I used).

As much as I'd like to know how to solve this problem and move on, I think it would be much better for me if I came to understand the underlying processes involved, so could anyone perhaps write a nice explanation for this? What I'm looking to know is the process.. It could look like this:

Step 1:

  • Input: Source code(s)
  • Process: Parsing (perhaps add more detail here)
  • Output: whatever is output here..

Step 2:

  • Input: Whatever was output from step 1, plus maybe whatever else is needed (libraries? DLLs? .so? .lib? )
  • Process: whatever is done with the input
  • Output: whatever is output

and so on..

Thanks..

Maybe this will explain what symbols are, what exactly "linking" is, what "object" code or whatever is..

Thanks.. Sorry for being such a noob..

P.S. This doesn't have to be language specific.. But feel free to express it in the language you're most comfortable in.. :)

EDIT: So anyway, I was able to get the errors resolved, it turns out that I have to manually add the .lib file to the project; simply specifying the library directory (where the .lib resides) in the IDE settings or project settings does not work..

However, the answers below have somewhat helped me understand the process better. Many thanks!.. If anyone still wants to write up a thorough guide, please do.. :)

EDIT: Just for additional reference, I found two articles by one author (Mike Diehl) to explain this quite well.. :)
Examining the Compilation Process: Part 1
Examining the Compilation Process: Part 2

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

心奴独伤 2024-07-19 09:35:49

两个主要步骤是编译和链接。

编译采用单个编译单元(这些只是源文件,及其包含的所有标头),并创建目标文件。 现在,在这些目标文件中,在特定位置(地址)定义了许多函数(以及其他内容,例如静态数据)。 在下一步链接中,还需要有关这些函数的一些额外信息:它们的名称。 所以这些也被存储起来。 单个目标文件可以引用实际上位于其他目标文件中的函数(因为它想在运行代码时调用它们),但由于我们在这里处理单个目标文件,因此只能使用符号引用(它们的“名称”)其他函数存储在目标文件中。

接下来是链接(这里我们只限于静态链接)。 链接是将第一步创建的目标文件(直接创建或将它们一起放入 .lib 文件后)组合在一起并创建可执行文件的位置。
在链接步骤中,通过在正确的对象中查找名称、查找函数的地址并将地址放在右侧,解析从一个目标文件或 lib 到另一个目标文件或 lib 的所有符号引用(如果可以的话)地方。

现在,解释一下您需要的有关“extern“C””的内容:

C 没有函数重载。 函数总是可以通过其名称来识别。 因此,当您将代码编译为 C 代码时,只有函数的真实名称存储在目标文件中。

然而,C++ 有一种叫做“函数/方法重载”的东西。 这意味着函数的名称不再足以识别它。 因此,C++ 编译器为包含函数原型的函数创建“名称”(因为名称加上原型将唯一标识一个函数)。 这称为“名称修改”。

当您想要使用从 C++ 项目编译为“C”代码的库(例如,预编译的 Lua 二进制文件)时,需要“extern“C””规范。

对于您的确切问题:如果仍然不起作用,这些提示可能会有所帮助:
* Lua 二进制文件是否使用相同版本的 VC++ 编译?
* 您可以简单地自己编译 Lua,无论是在您的 VC 解决方案中,还是作为 C++ 代码作为单独的项目?
* 您确定所有“外部“C””内容都正确吗?

The two main steps are compilation and linking.

Compilation takes single compilation units (those are simply source files, with all the headers they include), and create object files. Now, in those object files, there are a lot of functions (and other stuff, like static data) defined at specific locations (addresses). In the next step, linking, a bit of extra information about these functions is also needed: their names. So these are also stored. A single object file can reference functions (because it wants to call them when to code is run) that are actually in other object files, but since we are dealing with a single object file here, only symbolic references (their 'names') to those other functions are stored in the object file.

Next comes linking (let's restrict ourselves to static linking here). Linking is where the object files that were created in the first step (either directly, or after they have been thrown together into a .lib file) are taken together and an executable is created.
In the linking step, all those symbolic references from one object file or lib to another are resolved (if they can be), by looking up the names in the correct object, finding the address of the function, and putting the addresses in the right place.

Now, to explain something about the 'extern "C"' thing you need:

C does not have function overloading. A function is always recognizable by its name. Therefore, when you compile code as C code, only the real name of the function is stored in the object file.

C++, however, has something called 'function / method overloading'. This means that the name of a function is no longer enough to identify it. C++ compilers therefore create 'names' for functions that include the prototypes of the function (since the name plus the prototype will uniquely identify a function). This is known as 'name mangling'.

The 'extern "C"' specification is needed when you want to use a library that has been compiled as 'C' code (for example, the pre-compiled Lua binaries) from a C++ project.

For your exact problem: if it still does not work, these hints might help:
* have the Lua binaries been compiled with the same version of VC++?
* can you simply compile Lua yourself, either within your VC solution, or as a separate project as C++ code?
* are you sure you have all the 'extern "C"' things correct?

枉心 2024-07-19 09:35:49

您必须进入项目设置并在“链接器”选项卡上的某个位置添加一个包含 LUA 库 *.lib 文件的目录。 设置称为“包括库”或其他东西,抱歉我无法查找它。

您得到“无法解析的外部符号”的原因是因为 C++ 中的编译分两个阶段进行。 首先,代码被编译,每个 .cpp 文件都有自己的 .obj 文件,然后“链接器”启动并将所有 .obj 文件连接到 .exe 文件中。 .lib 文件只是一堆合并在一起的 .obj 文件,以使库的分发更加简单。
因此,通过添加所有“#include”和 extern 声明,您告诉编译器在某个地方可以找到具有这些签名的代码,但链接器找不到该代码,因为它不知道那些具有实际代码的 .lib 文件在哪里被放置。

确保您已阅读该库的 REDME,通常他们对将其包含在代码中必须执行的操作有相当详细的解释。

You have to go into project setting and add a directory where you have that LUA library *.lib files somewhere on the "linker" tab. Setting called "including libraries" or something, sorry I can't look it up.

The reason you get "unresolved external symbols" is because compilation in C++ works in two stages. First, the code gets compiled, each .cpp file in it's own .obj file, then "linker" starts and join all that .obj files into .exe file. .lib file is just a bunch of .obj files merged together to make distribution of libraries just a little bit simplier.
So by adding all the "#include" and extern declaration you told the compiler that somewhere it would be possible to find code with those signatures but linker can't find that code because it doesn't know where those .lib files with actual code is placed.

Make sure you have read REDME of the library, usually they have rather detailed explanation of what you had to do to include it in your code.

柠北森屋 2024-07-19 09:35:48

对于 C 和相关语言,从源代码到可执行文件通常是一个两阶段过程,尽管 IDE 可能将其呈现为单个过程。

1/ 您编写源代码并通过编译器运行它。 此阶段的编译器需要您的源代码和您要链接的其他内容的头文件(见下文)。

编译包括将源文件转换为目标文件。 对象文件包含您编译的代码和足够的信息来了解它们需要哪些其他内容,但在哪里可以找到其他内容(例如,LUA 库)。

2/ 下一阶段的链接是将所有目标文件与库组合起来以创建可执行文件。 我不会在这里讨论动态链接,因为这会使解释变得复杂,而且没有什么好处。

您不仅需要指定链接器可以找到其他代码的目录,还需要指定包含该代码的实际库。 事实上,您收到未解决的外部信息表明您还没有这样做。

作为示例,请考虑以下简化的 C 代码 (xx.c) 和命令。

#include <bob.h>
int x = bob_fn(7);

cc -c -o xx.obj xx.c

这会将 xx.c 文件编译为 xx.objbob.h 包含 bob_fn() 的原型,以便编译成功。 -c 指示编译器生成目标文件而不是可执行文件,-o xx.obj 设置输出文件名。

bob_fn() 的实际代码不在头文件中,而是在 /bob/libs/libbob.so 中,因此要链接,您需要类似的东西:

cc -o xx.exe xx.obj -L/bob/libs;/usr/lib -lbob

这会使用 libbob.soxx.obj 创建 xx.exe code> (lib 和 .so 通常由链接器添加)。 在此示例中,-L 设置库的搜索路径。 -l 指定一个库,以便在必要时查找包含在可执行文件中的库。 链接器通常采用“bob”并在-L指定的搜索路径中查找第一个相关库文件。

库文件实际上是目标文件的集合(类似于 zip 文件如何包含多个其他文件,但不一定是压缩的) - 当找到未定义外部的第一个相关出现时,将从库复制目标文件并添加到可执行文件,就像您的 xx.obj 文件一样。 这通常会持续到不再有未解决的外部问题为止。 “相关”库是“bob”文本的修改,它可能会查找 libbob.alibbob.dlllibbob.so >、bob.abob.dllbob.so 等。 相关性由链接器本身决定,并且应该记录下来。

它的工作原理取决于链接器,但基本上就是这样。

1/ 所有目标文件都包含需要解析的未解析外部文件的列表。 链接器将所有这些对象放在一起并修复它们之间的链接(解析尽可能多的外部对象)。

2/ 然后,对于每个未解析的外部仍然,链接器会梳理库文件,寻找可以满足链接的目标文件。 如果找到它,就会将其拉入 - 这可能会导致进一步未解决的外部问题,因为拉入的对象可能有自己的需要满足的外部列表。

3/ 重复步骤 2,直到不再有未解析的外部文件或无法从库列表中解析它们(这是您的开发位置,因为您没有包含 LUA 库文件)。

我之前提到的复杂性是动态链接。 这是您链接例程存根(某种标记)而不是实际例程的地方,稍后在加载时(当您运行可执行文件时)解析该例程。 Windows 通用控件等内容都位于这些 DLL 中,因此它们可以更改,而无需将对象重新链接到新的可执行文件中。

From source to executable is generally a two stage process for C and associated languages, although the IDE probably presents this as a single process.

1/ You code up your source and run it through the compiler. The compiler at this stage needs your source and the header files of the other stuff that you're going to link with (see below).

Compilation consists of turning your source files into object files. Object files have your compiled code and enough information to know what other stuff they need, but not where to find that other stuff (e.g., the LUA libraries).

2/ Linking, the next stage, is combining all your object files with libraries to create an executable. I won't cover dynamic linking here since that will complicate the explanation with little benefit.

Not only do you need to specify the directories where the linker can find the other code, you need to specify the actual library containing that code. The fact that you're getting unresolved externals indicates that you haven't done this.

As an example, consider the following simplified C code (xx.c) and command.

#include <bob.h>
int x = bob_fn(7);

cc -c -o xx.obj xx.c

This compiles the xx.c file to xx.obj. The bob.h contains the prototype for bob_fn() so that compilation will succeed. The -c instructs the compiler to generate an object file rather than an executable and the -o xx.obj sets the output file name.

But the actual code for bob_fn() is not in the header file but in /bob/libs/libbob.so, so to link, you need something like:

cc -o xx.exe xx.obj -L/bob/libs;/usr/lib -lbob

This creates xx.exe from xx.obj, using libraries (searched for in the given paths) of the form libbob.so (the lib and .so are added by the linker usually). In this example, -L sets the search path for libraries. The -l specifies a library to find for inclusion in the executable if necessary. The linker usually takes the "bob" and finds the first relevant library file in the search path specified by -L.

A library file is really a collection of object files (sort of how a zip file contains multiple other files, but not necessarily compressed) - when the first relevant occurrence of an undefined external is found, the object file is copied from the library and added to the executable just like your xx.obj file. This generally continues until there are no more unresolved externals. The 'relevant' library is a modification of the "bob" text, it may look for libbob.a, libbob.dll, libbob.so, bob.a, bob.dll, bob.so and so on. The relevance is decided by the linker itself and should be documented.

How it works depends on the linker but this is basically it.

1/ All of your object files contain a list of unresolved externals that they need to have resolved. The linker puts together all these objects and fixes up the links between them (resolves as many externals as possible).

2/ Then, for every external still unresolved, the linker combs the library files looking for an object file that can satisfy the link. If it finds it, it pulls it in - this may result in further unresolved externals as the object pulled in may have its own list of externals that need to be satisfied.

3/ Repeat step 2 until there are no more unresolved externals or no possibility of resolving them from the library list (this is where your development was at, since you hadn't included the LUA library file).

The complication I mentioned earlier is dynamic linking. That's where you link with a stub of a routine (sort of a marker) rather than the actual routine, which is later resolved at load time (when you run the executable). Things such as the Windows common controls are in these DLLs so that they can change without having to relink the objects into a new executable.

〆一缕阳光ご 2024-07-19 09:35:48

第 1 步 - 编译器:

  • 输入:源代码文件
  • 过程:解析源代码并翻译为机器代码
  • 输出:目标文件,其中包含:
    • 此对象中定义的符号名称,以及此对象文件“导出”的符号名称
    • 与此目标文件中定义的每个符号关联的机器代码
    • 未在此目标文件中定义的符号名称,但该目标文件中的软件所依赖的符号名称以及随后必须链接到的符号名称,即该目标文件“导入”的名称

步骤 2 - 链接:

  • 输入:
    • 第 1 步中的目标文件
    • 其他对象的库(例如来自操作系统和其他软件)
  • 过程:
    • 对于您要链接的每个对象
    • 获取该对象导入的符号列表
    • 在其他库中查找这些符号
    • 将相应的库链接到您的目标文件
  • 输出:单个可执行文件,其中包括来自所有库的机器代码您的所有对象,加上导入(链接)到您的对象的库中的对象。

Step 1 - Compiler:

  • Input: Source code file[s]
  • Process: Parsing source code and translating into machine code
  • Output: Object file[s], which consist[s] of:
    • The names of symbols which are defined in this object, and which this object file "exports"
    • The machine code associated with each symbol that's defined in this object file
    • The names of symbols which are not defined in this object file, but on which the software in this object file depends and to which it must subsequently be linked, i.e. names which this object file "imports"

Step 2 - Linking:

  • Input:
    • Object file[s] from step 1
    • Libraries of other objects (e.g. from the O/S and other software)
  • Process:
    • For each object that you want to link
    • Get the list of symbols which this object imports
    • Find these symbols in other libraries
    • Link the corresponding libraries to your object files
  • Output: a single, executable file, which includes the machine code from all all your objects, plus the objects from libraries which were imported (linked) to your objects.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文