LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1096|回复: 0

tr:ONLamp:make for Nonprogrammers

[复制链接]
发表于 2005-4-20 13:28:41 | 显示全部楼层 |阅读模式
我喜欢翻译 OReilly 的文档, 排版漂亮, 并且也容易懂
Published on ONLamp.com (http://www.onlamp.com/)
http://www.onlamp.com/pub/a/bsd/2005/03/24/FreeBSD_Basics.html
See this if you're having trouble printing code examples

make for Nonprogrammers
by Dru Lavigne
03/24/2005

make for Nonprogrammers 非程序员的 make 教程
假设你是一位典型的 FreeBSD 用户, 并且对 C 编程一无所知。但是,只要你用过 make world 来升级你的操作系统,或者曾经在你的 ports 中的某个地方运行过 make install 来安装程序,你就编译过 C 代码了。

本文介绍一些基础知识, 这样你就会知道命令的背后发生了什么事情。本文也介绍了在运行 make 命令时一些可用的选项。
Why C? 为什么要提到 C 呢?

你也许会奇怪,既然自己的目标不是成为 C 程序员, 为什么要关心 C 呢。 原因很简单: 大多数操作系统 (包括 FreeBSD) 都是用 C 写的,很多可执行的程序也是用 C 写的。 例如, 使用  file 命令来查看系统中安装的第三方程序:

  1. % file /usr/local/bin/* | more
复制代码

你会发现包括一些 Bourne shell 脚本,还有 perl 脚本, 但是剩下的都是编译自 C 源代码 的可执行文件,因此输出的大部分都是这样: "ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), for FreeBSD 5.3.0, dynamically linked (uses shared libs), stripped."

要知道, 你可以从来都不使用 make, 也照样能用 FreeBSD。 如果想将系统升级到一个新版本, 只要重新安装它就可以了。不要动内核。对, 内核也是用 C 写的, 这就是为什么在编译内核时要运行 make buildkernel 和 make installkernel 的原因。 不要安装 ports,总是使用 pkg_add -r 来安装软件。不需要安装 src 以及 ports 会为你节省多少硬盘空间啊...

但是, 这样你就不能利用一个开源的操作系统的所有好处了——除了便宜的价格之外。
make Basics 基础知识

好,那么什么是 make 呢? 根据 man make, 它控制了程序的依赖关系。 任何一个参与过软件项目的 C 程序员都可以告诉你, 项目中会有成百上千的源代码, 头文件和目标文件, 需要编译, 连接, 从而生成一个可执行的程序。 make 的任务就是保证所有事情以正确的顺序发生。

make 在执行的时候, 会在你运行 make 命令时所在的目录中读取一个 Makefile 文件。例如, 假如我在个人目录中运行:

  1. % cd
  2. % make
  3. make: no target to make.
复制代码

这个消息意思是目录中没有叫做 Makefile 的文件。但是, 假如我 (切换为超级用户) 在 ports 的某个位置运行相同的命令:

  1. # cd /usr/ports/shells/bash
  2. # make
复制代码

make 将访问互联网, 下载合适的源代码, 然后编译。 这是必要的, 因为要编译某个程序, 必须需要 C 源代码。

make 是如何知道访问互联网来下载源代码的呢?更重要的是, 它如何知道哪个特定 FTP 站点包含了它需要的源代码呢? 你一定会猜到, 这些指令是包含在那个目录的 Makefile 中。正是这样:

  1. # ls /usr/ports/shells/bash
  2. Makefile        files                pkg-descr        pkg-plist
  3. distinfo        pkg-deinstall        pkg-install
复制代码

如果你通读这个 Makefile,你会找到一个 MASTER_SITES 变量, 列出了包含所需的源代码的网站的 URL。

注意: 下载到的源代码跑到哪去了? Makefile 控制着, 将它复制到了 /usr/ports/distfiles,它是一个 tar 打包。接下来, 它将这个 tar 打包解压到你所在的目录,放在称为 work 的子目录下面。输入 make install clean 将删除 work 子目录——不输入 clean 的话, work 子目录就会保留下来。
Deciphering the Makefile for a Port 解密 port 的 Makefile

你无需故作勇敢地去面对一个 Makefile,无需费太多力气,因为大部分大写的变量都有自解释的名称。如果你遇到某个变量并不是那么容易懂, 或者是想俯瞰全局,知道每个变量做些什么, 那么就去看看解释 port Makefile 格式的文件

  1. % more /usr/ports/Mk/bsd.port.mk
复制代码

知道一些变量的含义也很有用。例如, 我可以搜索 MAN 变量,从而得知一个 port 会安装哪些手册页:

  1. % grep MAN /usr/ports/mail/postfix/Makefile
  2. MAN1=        mailq.1 newaliases.1 postalias.1 postcat.1 postconf.1 postdrop.1 \
  3. MAN5=        access.5 aliases.5 canonical.5 cidr_table.5 ldap_table.5 \
  4. MAN8=        bounce.8 cleanup.8 defer.8 error.8 flush.8 lmtp.8 local.8
复制代码

MAN 变量使用一个数字来表示手册页的章节。使用 grep 来搜索这个变量,我可以知道这个 port 会向第一章安装 6 个手册页, 第五章有 5 个手册页,第八章有 3 个。看来,如果我安装这个 port,我要花好多时间来阅读了!
make Targets 目标

除了使用 grep 来收集 Makefile 中的信息,也可以利用目标。目标是用来表述你在 make 命令之后,接着输入的表示动作的词的正确说法。例如, 你在构建一个 port 时肯定用过了 install 和 clean 目标。毫不奇怪, /usr/ports/Mk/bsd.port.mk 包含了所有编译 port 时,可用的目标的列表。用一个分页程序打开这个文件之后, 可以用 / 来搜索 Default targets 段落,从而找到这个列表:

  1. % more /usr/ports/Mk/bsd.port.mk
  2. /Default targets
复制代码

但是, 你会发现阅读 man ports 会更简单一些, 因为它更详细地解释了常用的目标。

如果你没做过任何比 make install 更复杂的事情, 你应该在一个测试系统中尝试所有的这些目标,因为它们可能不像你想的那样运作,即使你详细阅读了描述文档。

例如, 试试在 /usr/ports/shells/bash 中运行 make configure 而不是 make install。 最初, 这看上去仅仅是一个普通的编译, make 首先访问网络, 查找源代码, 解压缩, 为你的系统进行配置。 但是它并不真正地进行编译代码或是安装。

如果你仔细阅读 man ports,你会发现 make install 实际上是一系列的目标, 以这个顺序运行:config, fetch, checksum, depends, extract, patch, configure, build, 最后才是 install. 如果你指定了任何其他的目标, make 将从 config 开始, 运行接下来的目标, 直到运行了指定的目标。因此, make configure 运行了从 make config 到 make configure 之间的所有目标。

接下来, 在 /usr/ports/mail/postfix 中运行 make configure。make 进程开始运行, 根据你的互联网连接速度,过一阵子,你就会看到一个对话框,你可以在里面进行配置, 选择要传给配置脚本的选项。

这种事情也许以前困扰过你: 你运行了 make install, 离开电脑旁去做其他事, 几个小时后回来, 程序却还没编译好, 仅仅跳出一个对话框, 等待你的输入... 告诉你一个秘密: 如果一个 port 会跳出这种对话框, 那么总是会包含一个 scripts 子目录, 包含一个叫做 configure 的 dialog 脚本。如果你在进入那个 port 框架后看到了这样一个子目录, 就呆着别走, 等待编译开始前的交互设置。

Understanding make config 理解 make config

你也许会好奇 make configure 与 make config 的区别是什么。 前面我已经讲过, make configure 在很多目标之后才运行, 可能会也可能不会要求用户与一个 dialog 脚本交互。

与此对比, config 目标是第一个运行的, 并且总是有一个 dialog 脚本, 让你来修改 OPTIONS。注意 OPTIONS 是故意大写的, 因为它是一个 make 变量。

例如:

  1. # cd /usr/ports/multimedia/xmms
  2. # make config
  3. ===> No options to configure (没什么好配置的)
复制代码

这不奇怪, 因为这个 Makefile 不包含 OPTIONS:

  1. # grep -w OPTIONS /usr/ports/multimedia/xmms/Makefile
  2. #
复制代码

但是, 这个 Makefile 用到了 OPTIONS:

  1. # grep OPTIONS /usr/ports/graphics/kdegraphics3/Makefile
  2. OPTIONS=  IMLIB "Build Kuickshow, a fast and versatile image viewer" off \
复制代码

注意最后的 \ 意味着接下来后更多选项;要查看更多, 使用 grep -A 5 而不是 grep, 可以看到从 OPTIONS 之后开始的 5 行内容。

现在试试:

  1. # cd /usr/ports/graphics/kdegraphics3
  2. # make config
复制代码

会立即跳出一个对话框, 显示所有可能的选项。 Makefile 中启用的, 将默认是 on, 而没有启用的默认就是 off。 当你作出了自己的选择, 然后用 tab 将光标移到 OK 并选择, 你将会退回到提示符下,因为 make config 是第一个也是仅有的要运行的目标。

你知道 /var/db/ports 保存了你选择的 OPTIONS 吗?

  1. # more /var/db/ports/kdegraphics/options
  2. # This file is auto-generated by 'make config'.
  3. # No user-servicable parts inside!
  4. # Options for kdegraphics-3.3.2_2
  5. _OPTIONS_READ=kdegraphics-3.3.2_2
  6. WITHOUT_IMLIB=true
  7. WITHOUT_GPHOTO2=true
  8. WITHOUT_SANE=true
复制代码

你也可以在 port 的目录中, 使用 showconfig 目标来查看你的选择:

  1. # pwd
  2. /usr/ports/graphics/kdegraphics3

  3. # make showconfig
  4. ===> The following configuration options are set for kdegraphics-3.3.2_2:
  5.      IMLIB=off "Build Kuickshow, a fast and versatile image viewer"
  6.      GPHOTO2=off "Enable support for digital cameras"
  7.      SANE=off "Build Kooka, a SANE scanner frontend for KDE"
复制代码

Should you change your mind, you can always rerun make config. Alternatively, remove the config options using:

  1. # make rmconfig
  2. ===> Removing user-configured options for kdegraphics-3.3.2_2

  3. # more /var/db/ports/kdegraphics/options
  4. /var/db/ports/kdegraphics/options: No such file or directory
复制代码

Your World's Makefile 全局的 Makefile
快, 当你要升级整个操作系统, 或是安装一个内核, 你会在哪个目录, 来运行 make 命令?那个目录中必须有一个 Makefile, 否则 make 命令就会失败。看看这里:

  1. % more /usr/src/Makefile
复制代码

这是一个有趣的 Makefile, 以你以前可能用过的目标开始, 例如 buildworld, buildkernel, installkernel 以及 installworld。 但是, 搜索 Targets 你会找到这样一段:

  1. # Targets that begin with underscore are internal targets intended for
  2. # developer convenience only.  They are intentionally not documented and
  3. # completely subject to change without notice.
  4. #
  5. TGTS=        all all-man buildkernel buildworld checkdpadd clean \
  6.         cleandepend cleandir depend distribute distributeworld everything \
  7.         hierarchy install installcheck installkernel installkernel.debug\
  8.         reinstallkernel reinstallkernel.debug installworld \
  9.         kernel-toolchain libraries lint maninstall \
  10.         obj objlink regress rerelease tags toolchain update \
  11.         _worldtmp _legacy _bootstrap-tools _cleanobj _obj \
  12.         _build-tools _cross-tools _includes _libraries _depend
复制代码

注意: 在 ports 中试着 make 某个目标是很安全的, 最坏的结果是安装一个新的应用程序。 但是, 如果你迫切地想脱离常规, 不使用 Handbook 手册描述的关于安全升级系统/内核的 make 目标, 那么就在一个测试系统中去做, 如果出错, 丢失了任何数据, 你也不会后悔。

Makefile 的其余部分描述了上面列出的那些目标。要注意一些有趣的事情, 请查看 Handbook 手册对 make world 的警告。Makefile 中解释得更多:

  1. #
  2. # world
  3. #
  4. # Attempt to rebuild and reinstall everything. This target is not to be
  5. # used for upgrading an existing FreeBSD system, because the kernel is
  6. # not included. One can argue that this target doesn't build everything
  7. # then.
  8. #
  9. world:
  10.         @echo "WARNING: make world will overwrite your existing FreeBSD"
  11.         @echo "installation without also building and installing a new"
  12.         @echo "kernel.  This can be dangerous.  Please read the handbook,"
  13.         @echo "'Rebuilding world', for how to upgrade your system."
  14.         @echo "Define DESTDIR to where you want to install FreeBSD,"
  15.         @echo "including /, to override this warning and proceed as usual."
  16.         @echo "You may get the historical 'make world' behavior by defining"
  17.         @echo "HISTORICAL_MAKE_WORLD.  You should understand the implications"
  18.         @echo "before doing this."
  19.         @echo ""
  20.         @echo "Bailing out now..."
复制代码

这个文件也指出 make kernel 实际上是 make buildkernel 随后是 make installkernel。这意味着你可以用:

  1. # make buildkernel KERNCONF=NEW && make installkernel KERNCONF=NEW
复制代码

来代替

  1. # make kernel KERNCONF=NEW
复制代码

注意如果你不用 KERNCONF 指定另一个内核, Makefile 就假定是 GENERIC。

我想提到的最后一个目标是 make update。如果你试着输入这个命令, 你只会立即退回到提示符下, 什么都没有发生。 这是因为这个文件会读取 /etc/make.conf 来查看你究竟要升级什么。

在我的测试机器上, 我的 cvsup 正在运行, 已经在 /root/cvs-supfile 中创建了一个 sup。因此, 我向 /etc/make.conf 中添加这些:

  1. SUP_UPDATE=                yes
  2. SUP=                        /usr/local/bin/cvsup
  3. SUPFLAGS=                -g -L 2
  4. SUPFILE=                /root/cvs-supfile
复制代码

注意:为了使这个例子可以顺利进行, 必须安装 cvsup-without-gui, 并且已经在指定位置配置了一个 SUPFILE。如果你安装了 cvsup-without-gui 但是没有创建 SUPFILE, 将 SUPFILE= 一行替换为下面这些:

  1. SUPHOST=                cvsup.ca.freebsd.org       
  2. SUPFILE=                /usr/share/examples/cvsup/standard-supfile
  3. PORTSSUPFILE=                /usr/share/examples/cvsup/ports-supfile
  4. DOCSUPFILE=                /usr/share/examples/cvsup/doc-supfile
复制代码

当填写 SUPHOST= 的时候, 请选择一个地理上与你接近的镜像。 另外, 检查 /usr/share/examples/cvsup 中的这三个文件, 选择你要升级系统/port/docs 的哪些部分。

当你结束后, 在 /usr/src 目录运行 make update, 来更新指定的源。
Conclusion 结语

你也许会好奇, 邮件列表上的人是如何知道 make install 之外的其他命令的。 现在你应该知道他们读了哪些文件来获取这些信息了。要记住, 如果要试验一些新的目标, 还是用一个测试系统为好, 并且先备份很重要的数据。

Dru Lavigne is an instructor at Marketbridge Technologies in Ottawa and the maintainer of the Open Protocol Resource.

Related Reading

Managing Projects with GNU make, 3rd Edition
By Robert Mecklenburg
Table of Contents
Index
Sample Chapter

Return to the BSD DevCenter.

Copyright © 2004 O'Reilly Media, Inc.
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表