# 4.1 Port 工作原理

好的，看来这并不像想象中那样简单，Port 需要一些修改才能正常工作。在本节中，我们将逐步解释如何修改它，以使其适应 Ports 的使用模式。

***

首先，当用户在 Port 目录下输入 `make` 时，会发生以下事件。阅读 **bsd.port.mk** 的相关内容能帮助更好地理解这一过程，建议在另一个窗口打开 **bsd.port.mk** 进行参考。

但别担心，并没有多少人完全理解 **bsd.port.mk** 的工作原理… *:-)*

1. **fetch** 目标运行。`fetch` 目标负责确保 tarball 文件存在于本地的 `DISTDIR` 中。如果 `fetch` 在 `DISTDIR` 找不到所需的文件，它会查找 **Makefile** 中定义的 `MASTER_SITES` URL，或者我们将 distfiles 放入的 FTP 镜像站点作为备份。它将尝试使用 `FETCH` 下载指定的分发文件，假设请求的站点可以直接访问互联网。如果下载成功，文件将保存在 `DISTDIR` 中供将来使用，然后继续进行下一步。
2. **extract** 目标运行。该目标会在 `DISTDIR` 中查找 Port 的分发文件（通常是压缩的 tarball 文件），并将其解压到指定的临时子目录 `WRKDIR` 中（默认是 **work**）。
3. **patch** 目标运行。首先，应用在 `PATCHFILES` 中定义的补丁。其次，如果在 `PATCHDIR` 中找到任何名为 **patch-**\* 的补丁文件（默认位于 **files** 子目录中），则按字母顺序在此时应用它们。
4. **configure** 目标运行。这个目标可以执行许多不同的操作。
   1. 如果存在，则运行 **scripts/configure**。
   2. 如果设置了 `HAS_CONFIGURE` 或 `GNU_CONFIGURE`，则运行 **WRKSRC/configure**。
5. **build** 目标运行。该目标负责进入 Port 的私有工作目录（`WRKSRC`）并进行编译。
6. **stage** 目标运行。这个目标将最终构建好的文件放入一个临时目录（`STAGEDIR`，请参见 [Staging](https://docs.freebsd.org/en/books/porters-handbook/special/#staging)）。该目录的层级结构与将要安装该包的系统相似。
7. **package** 目标运行。这个目标会根据 `stage` 目标期间创建的临时目录中的文件以及 Port 的 **pkg-plist** 来创建一个包。
8. **install** 目标运行。这个目标将通过 `package` 目标创建的包安装到主机系统中。

以上是默认的操作步骤。此外，可以定义 `pre-something` 或 `post-something` 目标，或在 **scripts** 子目录中放置相应的脚本，它们将在默认操作前后执行。

例如，如果 **Makefile** 中定义了 `post-extract` 目标，并且 **scripts** 子目录中有一个 **pre-build** 文件，那么 `post-extract` 目标将在常规的解压操作之后被调用，而 **pre-build** 文件则会在默认的构建规则之前执行。建议在操作较简单时使用 **Makefile** 目标，因为这样更容易让其他人理解 Port 需要什么样的非默认操作。

默认的操作由 **bsd.port.mk** 中的 `do-something` 目标完成。例如，解压 Port 的命令位于 `do-extract` 目标中。如果默认目标没有正确执行某个操作，可以重新定义 **Makefile** 中的 `do-something` 目标。

> **注意**
>
> “主要”目标（例如 `extract`、`configure` 等）只不过是确保所有前置阶段都已完成，然后调用真正的目标或脚本，它们不应该被修改。要修复解压问题，就修改 `do-extract`，但绝不能改变 `extract` 的操作！另外，`post-deinstall` 目标无效，Port 基础设施不会运行它。

了解了用户输入 `make install` 时的操作流程之后，接下来我们将逐步介绍如何创建完美的 Port。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://porters-handbook.bsdcn.org/di-4-zhang-fu-za-de-port/4.1.-ta-shi-zen-mo-yun-zuo-de.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
