英语法语西班牙语

Ad


OnWorks 网站图标

缺点 - 在云端在线

通过 Ubuntu Online、Fedora Online、Windows 在线模拟器或 MAC OS 在线模拟器在 OnWorks 免费托管服务提供商中运行缺点

这是可以使用我们的多个免费在线工作站之一在 OnWorks 免费托管服务提供商中运行的命令缺点,例如 Ubuntu Online、Fedora Online、Windows 在线模拟器或 MAC OS 在线模拟器

程序:

您的姓名


缺点 - 一个软件构建系统

商品描述


2.2.0 版指南和参考

版权所有 (c) 1996-2000 Free Software Foundation, Inc.

该程序是免费软件; 您可以根据以下条款重新分发和/或修改它
由自由软件基金会发布的 GNU 通用公共许可证; 任何一个
许可的第2版,或(由您选择)任何更高版本。

分发此程序是希望它有用,但不作任何保证;
甚至没有对适销性或针对特定目的的适用性的暗示保证。
有关更多详细信息,请参阅 GNU 通用公共许可证。

您应该已经收到一份 GNU 通用公共许可证以及该程序;
请参阅文件复制。 如果没有,请写信给 Free Software Foundation, Inc., 59 Temple
地点 - Suite 330, Boston, MA 02111-1307, USA。

介绍


缺点 是一个主要用于构建软件的系统,但与
以前的软件构建系统。 缺点是从头开始设计的
轻松构建分布在多个源目录中的软件。 缺点
使创建简单、易懂和可维护的构建脚本变得容易。
缺点确保复杂的软件可以轻松准确地重现。

Cons 使用多种技术来完成所有这些。 构建脚本只是
Perl 脚本,使它们既易于理解又非常灵活。 全球范围
变量被替换为用于共享信息的导入/导出机制
脚本,显着提高了每个脚本的可读性和可维护性。
建设 环境中 介绍:这些是捕获
控制构建过程所需的信息。 多环境使用
当在构建树中生成产品需要不同的语义时。 缺点
实现自动依赖分析并使用它来全局排序整个
建造。 变体构建很容易从单个源树生成。 智能构建
在处理本地化更改时,子集是可能的。 可以设置覆盖
无需修改任何脚本即可轻松覆盖构建指令。 MD5 加密
签名 与派生文件相关联,用于准确判断是否
需要重建给定的文件。

在提供上述所有功能以及更多功能的同时,缺点仍然简单易用。 这会,
希望您在阅读本文档的其余部分时变得清晰。

为什么 缺点? 为什么 不能 使?


缺点是 使 替代品。 在下面的段落中,我们将看看其中的一些
make 的不良特征——以及基于 make 的典型构建环境——
推动了 Cons 的发展。

建立 复杂

任何规模的传统基于品牌的系统都趋于变得相当复杂。 原作
效用及其衍生品在许多方面促成了这种趋势。 使是
不擅长处理分布在多个目录中的系统。 各种工作——
周围就是用来克服这个困难的; 通常的选择是 make 调用
对于构建的每个子目录,它自己递归。 这导致复杂的代码,在
通常不清楚变量是如何设置的,或者变量的设置有什么影响
将在整体上构建。 make 脚本语言逐渐被扩展
提供更多的可能性,但这些在很大程度上使已经
过度扩展的语言。 通常,构建是在多次传递中完成的,以便提供
适当的产品从一个目录到另一个目录。 这代表进一步
增加构建复杂性。

建立 再生性

所有 make 的祸根一直是正确处理依赖关系。 大多数情况下,一个
尝试在单个目录中执行合理的依赖关系工作,但没有
认真尝试在目录之间完成这项工作。 即使依赖是
工作正常,依靠简单的时间戳比较来确定是否
一个文件对于它的受抚养人来说已经过时了,一般来说,不足以
确定何时应重新派生文件。 例如,如果外部库是
重建然后“捕捉”到位,其新创建的文件上的时间戳可能
最好早于上次本地构建,因为它是在它变得可见之前构建的。

变种 建立

Make 仅提供有限的工具来处理变体构建。 随着扩散
硬件平台的需求以及对可调试与优化代码的需求,能够
轻松创建这些变体至关重要。 更重要的是,如果创建了变体,它
重要的是能够分离变体或能够重现
随意原始或变体。 使用 make 很难将构建分成
多个构建目录,与源分开。 如果不使用这种技术,
几乎不可能在任何给定时间保证哪个变体存在于
树,而无需完全重建。



Make 仅对从存在于
中央存储库目录结构。 GNU make 的 VPATH 特性(以及其他一些
make implementations) 旨在提供此功能,但无法按预期工作:它
在分析中过早地将目标文件的路径更改为 VPATH 名称,因此
在 VPATH 目录中搜索所有依赖项。 确保正确开发
构建,重要的是能够在本地构建目录中创建文件并具有
代码存储库(VPATH 目录,在 make 术语中)中依赖于本地的任何文件
文件得到正确重建。 这在 VPATH 中是不可能的,无需编写大量代码
将复杂的存储库知识直接导入到 makefile 中。

保持 it 简单


上面已经引用了 make 的一些困难。 在这次和随后的
部分,我们将介绍缺点并展示如何解决这些问题。

Perl的 脚本

缺点是基于 Perl。 也就是说,Cons 脚本——征募建设 文件,相当于
生成文件 or 生成文件-- 都是用 Perl 写的。 这提供了一个直接的好处:
用于编写脚本的语言是一种熟悉的语言。 即使你不是 Perl
程序员,知道 Perl 基本上只是一种简单的声明性语言会有所帮助,
具有明确定义的控制流和熟悉的语义。 它有行为的变量
基本上是你期望的方式,子程序,控制流等等。 那里
没有为 Cons 引入特殊语法。 使用 Perl 作为脚本语言
简化了为通常复杂的问题表达适当解决方案的任务
构建的要求。

你好, 世界!

为了为以下讨论打下基础,这里是您如何构建 你好, 世界! C
有缺点的应用程序:

$env = 新的缺点();
程序 $env 'hello', 'hello.c';

如果您将此脚本安装在目录中,请命名该脚本 建设,然后创建
你好ç 源文件在同一目录中,然后您可以键入`cons hello'来构建
应用程序:

% 缺点 你好
cc -c 你好.c -o 你好.o
cc -o 你好你好.o

建设 环境中

Cons 的一个关键简化是 施工 环境. 一个建筑
环境是一个 对象 由一组键/值对和一组 方法。
为了告诉 Cons 如何构建一些东西,你通过调用适当的方法
适宜的施工环境。 考虑以下示例:

$env = 新的缺点(
CC => 'gcc',
LIBS => 'libworld.a'
);

程序 $env 'hello', 'hello.c';

在这种情况下,而不是使用默认的构建环境,我们有
覆盖“CC”的值,以便使用等效的 GNU C 编译器。 自从
这个版本 你好, 世界! 需要一个图书馆, libworld.a,我们已经指定任何
在此环境中链接的程序应与该库链接。 如果图书馆
已经存在,很好,但如果不存在,那么我们还必须包含以下语句:

图书馆 $env 'libworld', 'world.c';

现在,如果你输入‘cons hello’,库将在程序链接之前构建,并且,
当然,`gcc' 将用于编译这两个模块:

% 缺点 你好
gcc -c 你好.c -o 你好.o
gcc -c 世界.c -o 世界.o
a r libworld.a world.o
ar:创建 libworld.a
ranlib libworld.a
gcc -o 你好你好.o libworld.a

自动表 完成 依赖 分析

使用 Cons,自动处理依赖项。 继续前面的例子,注意
当我们修改 世界.c, 世界.o 重新编译, libworld.a 重新创建,和 hello
重新链接:

% vi 世界.c
[编辑]
% 缺点 你好
gcc -c 世界.c -o 世界.o
a r libworld.a world.o
ar:创建 libworld.a
ranlib libworld.a
gcc -o 你好你好.o libworld.a

这是一个相对简单的例子:Cons ``知道'' 世界.o 取决于 世界.c因为
依赖是由`Library' 方法显式设置的。 它也知道 libworld.a
取决于 世界.ohello 取决于 libworld.a,都是出于类似的原因。

现在事实证明 你好ç 还包括接口定义文件, 世界.h:

% emacs 世界.h
[编辑]
% 缺点 你好
gcc -c 你好.c -o 你好.o
gcc -o 你好你好.o libworld.a

Cons 怎么知道的 你好ç 包括 世界.h,而 你好 因此必须是
重新编译? 现在,只要说在考虑是否 你好 起来了——
迄今为止,Cons 为其依赖调用扫描器, 你好ç. 该扫描仪列举了
包含的文件 你好ç 列出更多依赖项,除此之外
由 Cons 脚本明确表示。 这个过程是递归的:包含的任何文件
包含的文件也将被扫描。

这不是很贵吗? 答案是——视情况而定。 如果你做一个大型系统的完整构建,
扫描时间是微不足道的。 如果你重建一个大型系统,那么 Cons 将
花相当长的时间考虑它,然后才决定什么都不必
完成(虽然不一定比制作时间多!)。 好消息是 Cons 做到了
当您进行本地化更改时,很容易智能地对您的构建进行子集化。

自动表 全球化 建立 测序

因为 Cons 进行了全面而准确的依赖分析,并且在全局范围内进行,对于
整个构建,Cons 能够使用这些信息来完全控制 测序
的构建。 这种顺序在上面的例子中很明显,并且等同于
考虑到完整的依赖关系,您会期望 make 。 有了缺点,这扩展了
对更大的多目录构建来说很简单。 因此,所有涉及的复杂性
确保构建正确组织 - 包括多通道分层
构建 - 被淘汰。 我们将在接下来的部分中进一步讨论这一点。

建筑物 树——仍然 只是 as 简单


A 等级制度 of 建立 脚本

在 Cons 中,一个更大的构建是通过创建一个层次结构来组织的 建立 脚本. 在顶部
树的一个脚本叫做 建设. 按照惯例,其余的脚本都是
被称为 征募. 这些脚本非常简单地通过“构建”连接在一起,
“导出”和“导入”命令。

建立 命令

`Build' 命令需要一个列表 征募 文件名,并安排他们
包含在构建中。 例如:

构建 qw(
司机/显示器/应征者
驱动程序/鼠标/应征者
解析器/应征者
公用事业/应征者
);

这是一个简单的两级构建脚本层次结构:所有附属 征募
在顶层提到 建设 文件。 请注意,并非树中的所有目录
必须有与之关联的构建脚本。

这也可以编写为多级脚本。 例如, 建设 文件可能
包含这个命令:

构建 qw(
解析器/应征者
司机/应征者
公用事业/应征者
);

征募 文件中 驱动程序 目录可能包含:

构建 qw(
显示/应征
鼠标/应征者
);

经验表明,前一种模型更容易理解,因为
整个构建树都在你的面前,在顶层。 混合方案是
也可以。 需要合并到一个单独维护的组件中
例如,构建树可能会在一个地方与构建树挂钩,但定义它自己的
构造层次。

默认情况下,Cons 不会将其工作目录更改为包含
征募 它包含的文件。 可以通过以下方式为构建启用此行为
指定,在顶级 建设 文件:

征兵_chdir 1;

启用后,缺点将更改为子公司 征募 文件的包含目录
在读入该文件时,然后将文件更改回顶级目录
已处理。

预计此行为将成为 Cons 的某些未来版本中的默认设置。
为了准备这种转变,期望 Cons 保持在构建顶部的构建
当它在子公司中读取时 征募 文件应明确禁用此功能
如下:

征兵_chdir 0;

相对的, 顶级亲戚, 绝对 文件 名称

您可能已经注意到,为 Build 命令指定的文件名是相对于
调用它的脚本的位置。 这通常适用于其他文件名
其他命令的参数,虽然我们不妨在这里提到,如果你开始
带有井号“#”的文件名,然后该文件相对于顶部 -
级别目录(其中 建设 文件驻留)。 而且,毫不奇怪,如果你开始
带有“/”,那么它被认为是一个绝对路径名。 即使在系统上也是如此
使用反斜杠而不是正斜杠来命名绝对路径。

运用 模块 in 建立 脚本

您可以将模块拉入每个 征募 使用普通 Perl 的“use”或“require”文件
声明:

使用英语;
需要我的::模块;

每个“使用”或“要求”只影响一个 征募 它出现的文件。 使用一个
多个模块 征募 文件,您必须在每个文件中放置一个“use”或“require”语句
一个需要模块的。

范围 of 变量

顶级的 建设 文件和所有 征募 文件开始于一个共同的、独立的 Perl
包。 缺点 控制包的符号表,以便
每个脚本都是空的,除了 建设 文件,它获取一些命令行
论据。 因此,所有设置或使用的变量都由脚本设置
本身——不是通过一些外部脚本。

变量可以显式 通过来自其父脚本的脚本。 导入一个
变量,应该是 出口 由父级初始化(否则错误
会发生)。

出口 命令

“导出”命令的使用如下例所示:

$env = 新的缺点();
$INCLUDE = "#export/include";
$LIB = "#export/lib";
导出 qw( env INCLUDE LIB );
构建 qw( util/Conscript );

`Export' 列表中提到的简单变量的值将被删除
通过任何后续的“构建”命令。 `Export' 命令只会导出 Perl 纯量
变量,即名称以“$”开头的变量。 其他变量、对象等。
可以通过引用导出——但所有脚本都将引用同一个对象,这
对象应被附属脚本和原始脚本视为只读
导出脚本。 但是,为导出的标量分配一个新值是可以接受的
变量——不会改变引用的基础变量。 这个序列,对于
例如,没问题:

$env = 新的缺点();
导出 qw( env INCLUDE LIB );
构建 qw( util/Conscript );
$env = new cons(CFLAGS => '-O');
建立qw(其他/应征者);

变量是在“导出”命令之前还是之后设置都没有关系。 这
重要的是执行`Build'命令时变量的值。
这就是松鼠离开的原因。 顺便说一下,任何后续的“导出”命令,
使第一个无效:您必须提及您希望在每个变量上导出的所有变量
“导出”命令。

进口 命令

“导出”命令导出的变量可以通过
“导入”命令。 辅助脚本总是直接从
高级脚本。 考虑这个例子:

导入 qw( env INCLUDE );

这仅在父脚本同时导出 `$env' 和 `$INCLUDE' 时才合法。 它也必须
已经给出了这些变量中的每一个值。 附属脚本只可以
导入导出变量的子集(在本例中为“$LIB”,它由
上一个示例,未导入)。

所有导入的变量都会自动重新导出,所以序列:

导入 qw ( env INCLUDE );
建造 qw (under-me/Conscript );

将为附属文件提供`$env'和`$INCLUDE'。 如果只有 `$env' 是
导出,那么以下就足够了:

导入 qw ( env INCLUDE );
导出 qw ( env );
建造 qw (under-me/Conscript );

不用说,在调用 `Build' 之前,可以在本地修改变量
辅助脚本。

建立 脚本 评估 秩序

构建脚本排序的唯一限制是高级脚本是
在他们的劣等剧本之前进行评估。 顶级的 建设 例如,文件是
首先评估,然后是任何劣质脚本。 这就是你真正需要知道的
关于评估顺序,因为顺序通常无关紧要。 考虑以下
“构建”命令:

构建 qw(
司机/显示器/应征者
驱动程序/鼠标/应征者
解析器/应征者
公用事业/应征者
);

我们选择按字母顺序排列脚本名称,只是因为这是最
便于维护。 更改顺序不会对
建立。

A 型号 共享


简单 公约

在任何复杂的软件系统中,都需要一种共享构建产品的方法
已确立的。 我们提出了一组简单的约定,这些约定很容易实现
缺点,但非常有效。

基本规则是要求所有需要共享的构建产品
目录通过中间目录共享。 我们通常称之为
出口, 并且,在 C 环境中,提供该目录的常规子目录,
包括, LIB, 箱子等等。

这些目录由顶层定义 建设 文件。 一个简单的 建设 文件
a 你好, 世界! 使用多个目录组织的应用程序可能如下所示:

# 为 Hello, World! 构建文件

# 在哪里放置我们所有的共享产品。
$EXPORT = '#export';

导出 qw( CONS INCLUDE LIB BIN );

# 共享产品的标准目录。
$INCLUDE = "$导出/包含";
$LIB = "$EXPORT/lib";
$BIN = "$EXPORT/bin";

# 一个标准的构建环境。
$CONS = 新的缺点 (
CPPPATH => $INCLUDE, # 包含 C 编译的路径
LIBPATH => $LIB, # 链接程序的库路径
LIBS => '-lworld', # 标准库列表
);

构建 qw(
你好/应征者
世界/应征者
);

世界 目录的 征募 文件如下所示:

# 目录世界的征召文件
导入 qw(缺点包括 LIB);

# 安装该目录下的产品
安装 $CONS $LIB, 'libworld.a';
安装 $CONS $INCLUDE, 'world.h';

# 内部产品
图书馆 $CONS 'libworld.a', 'world.c';

hello 目录的 征募 文件如下所示:

# 目录 hello 的 Conscript 文件
导入 qw(CONS BIN);

# 出口产品
安装 $CONS $BIN, 'hello';

# 内部产品
程序 $CONS 'hello', 'hello.c';

构建一个 你好, 世界! 具有此目录结构的程序,转到顶层
目录,并使用适当的参数调用“cons”。 在下面的例子中,我们
告诉 Cons 建立目录 出口. 为了构建目录,Cons 递归地构建所有
该目录中的已知产品(当然,仅当它们需要重建时)。 如果其中任何一个
这些产品依赖于其他目录中的其他产品,然后将构建这些产品,
了。

% 缺点出口
将 world/world.h 安装为 export/include/world.h
cc -Iexport/include -c hello/hello.c -o hello/hello.o
cc -Iexport/include -c world/world.c -o world/world.o
ar r 世界/libworld.a 世界/world.o
ar:创造世界/libworld.a
Ranlib 世界/libworld.a
将 world/libworld.a 安装为 export/lib/libworld.a
cc -o 你好/你好你好/hello.o -Lexport/lib -lworld
将 hello/hello 安装为 export/bin/hello

清洁, 可以理解, 位置无关 脚本

你会注意到这两个 征募 文件非常干净,切中要害。 他们只是
指定目录的产品以及如何构建这些产品。 构建说明
最小:它们指定要使用的构建环境、产品名称、
和输入的名称。 另请注意,脚本与位置无关:如果您
希望重新组织您的源代码树,您可以自由地这样做:您只需要更改
建设 文件(在本例中),指定新的位置 征募 文件。 的
使用导出树使这个目标变得容易。

还要注意 Cons 如何为您处理小细节。 一切 出口 目录,对于
例如,是自动生成的。 并且安装的文件确实硬链接到
各自的导出目录,以节省空间和时间。 这种对细节的关注可以节省
大量的工作,并使生成简单、可维护的脚本变得更加容易。

分离 资源 建立


通常希望将构建中的任何派生文件与构建完全分开
源文件。 这使得跟踪源文件的内容变得更加容易,并且
也使处理更简单 变种 构建,特别是如果您想要变体构建
共存。

分离 建立 资源 目录 运用 链接 命令

Cons 提供了一种简单的机制来处理所有这些要求。 “链接”
命令在本例中被调用:

链接 'build' => 'src';

指定的目录“链接”到指定的源目录。 让我们假设
你设置了一个源目录, SRC, 与子目录 世界hello 在它下面,
就像前面的例子一样。 然后,您可以替换原始构建行
在以下:

构建 qw(
建造/世界/征兵
建造/你好/征兵
);

请注意,您对待 征募 文件就好像它存在于构建目录中一样。 现在如果
您输入与之前相同的命令,您将获得以下结果:

% 缺点出口
将 build/world/world.h 安装为 export/include/world.h
cc -Iexport/include -c build/hello/hello.c -o build/hello/hello.o
cc -Iexport/include -c build/world/world.c -o build/world/world.o
ar r build/world/libworld.a build/world/world.o
ar:创建 build/world/libworld.a
ranlib 构建/世界/libworld.a
安装 build/world/libworld.a 作为 export/lib/libworld.a
cc -o 构建/你好/你好构建/你好/hello.o -Lexport/lib -lworld
将 build/hello/hello 安装为 export/bin/hello

同样,Cons 已为您处理好细节。 特别是,您会注意到所有
构建是使用构建目录中的源文件和目标文件完成的。 为了
例, 构建/世界/world.o 编译自 构建/世界/world.c
出口/包括/world.h 安装自 构建/世界/world.h. 这是在大多数情况下完成的
通过“硬”链接来自每个源的所需文件的简单权宜之计
目录到适当的构建目录。

无论您对源目录做什么,Cons 都会正确维护链接。
如果您修改源文件,您的编辑器可能会“就地”执行此操作,或者可能会重命名它
首先创建一个新文件。 在后一种情况下,任何硬链接都将丢失。 缺点会
下次需要源文件时检测这种情况,并将重新链接它
适当。

顺便说一下,你还会注意到 没有 需要改变底层 征募
文件。 我们可以走得更远,我们将在下一节中看到。

变种 建立


你好, 世界! 香蕉 操作系统的

变体构建只需要另一个简单的扩展。 让我们以一个例子为例
要求允许构建 baNaNa 和 peAcH 操作系统。 在这种情况下,
我们正在使用分布式文件系统,例如 NFS 来访问特定系统,并且
对于任何给定的调用,只需编译一个或另一个系统
‘缺点’。 这是我们可以设置的一种方法 建设 为我们的文件 你好, 世界!
应用程序:

# 为 Hello, World! 构建文件

die qq(必须指定OS)除非$OS = $ARG{OS};
die qq(操作系统必须是“桃子”或“香蕉”)
if $OS ne "peach" && $OS ne "banana";

# 在哪里放置我们所有的共享产品。
$EXPORT = "#export/$OS";

导出 qw( CONS INCLUDE LIB BIN );

# 共享产品的标准目录。
$INCLUDE = "$导出/包含";
$LIB = "$EXPORT/lib";
$BIN = "$EXPORT/bin";

# 一个标准的构建环境。
$CONS = 新的缺点 (
CPPPATH => $INCLUDE, # 包含 C 编译的路径
LIBPATH => $LIB, # 链接程序的库路径
LIBS => '-lworld', # 标准库列表
);

# $BUILD 是我们将获得一切的地方。
$BUILD = "#build/$OS";

# 告诉 cons $BUILD 的源文件在哪里。
链接 $BUILD => 'src';

建造 (
"$BUILD/hello/Conscript",
"$BUILD/world/Conscript",
);

现在,如果我们登录到 peAcH 系统,我们可以构建我们的 你好, 世界! 申请
平台:

% 缺点导出操作系统=桃子
安装 build/peach/world/world.h 作为 export/peach/include/world.h
cc -Iexport/peach/include -c build/peach/hello/hello.c -o build/peach/hello/hello.o
cc -Iexport/peach/include -c build/peach/world/world.c -o build/peach/world/world.o
ar r build/peach/world/libworld.a build/peach/world/world.o
ar:创建 build/peach/world/libworld.a
ranlib 构建/peach/world/libworld.a
安装 build/peach/world/libworld.a 作为 export/peach/lib/libworld.a
cc -o 构建/peach/hello/hello 构建/peach/hello/hello.o -Lexport/peach/lib -lworld
安装 build/peach/hello/hello 作为 export/peach/bin/hello

变化 on a 主题

该模型的其他变体是可能的。 例如,您可能决定要
将您的包含文件分离为平台相关文件和平台独立文件。
在这种情况下,您必须为平台相关的“$INCLUDE”定义一个替代方案
文件。 最多 征募 文件,生成完全独立于平台的包含文件,将
不必改变。

您可能还希望能够通过调试或分析来编译整个系统,
例如,启用。 您可以使用适当的命令行选项执行此操作,例如
`调试=开'。 然后这将被转换为适当的特定于平台的
启用调试的要求(这可能包括关闭优化,对于
例子)。 您可以选择为这些不同类型的系统更改名称空间,
但是,正如我们将在下一节中看到的,它不是 必要 这样做,因为缺点很漂亮
当你改变选项时,聪明地重建事物。

签名


MD5 加密 签名

每当 Cons 创建派生文件时,它都会存储一个 签名 对于那个文件。 签名
存储在一个单独的文件中,每个目录一个。 前面的例子编译完成后,
。交付 文件中 建造/桃子/世界 目录如下所示:

world.o:834179303 23844c0b102ecdc0b4548d1cd1cbd8c6
libworld.a:834179304 9bf6587fa06ec49d864811a105222c00

第一个数字是时间戳——对于 UNIX 系统,这通常是
自 1 年 1970 月 5 日以来的秒数。第二个值是 MDXNUMX 校验和。 这 想说的话 消化
算法 是一种算法,给定输入字符串,计算强密码
该字符串的签名。 MD5 校验和存储在 。交付 文件实际上是一个
指定文件的所有依赖信息的摘要。 因此,例如,对于
世界.o 文件,这至少包括 世界.c 文件,以及任何不符合要求的头文件
知道这些被直接或间接地包括在内 世界.c。 不仅如此,
用于生成的实际命令行 世界.o 也被输入到计算中
签名。 相似地, libworld.a 得到一个“包括”所有的签名
其组成部分的签名(因此,传递性地,
成分),以及创建文件的命令行。

默认情况下,非派生文件的签名是通过采用当前
文件的修改时间和文件的条目名称(除非碰巧有
当前 。交付 该文件的条目,在这种情况下使用该签名)。

请注意,派生文件不需要依赖于任何特定的 建设 or
征募 文件--如果对这些文件的更改会影响相关文件,那么这将是
自动反映在其签名中,因为命令行的相关部分是
包含在签名中。 无关的更改将不起作用。

当 Cons 考虑是否派生一个特定的文件时,它首先计算
文件的预期签名。 然后将文件的上次修改时间与
时间记录在 。交付 条目,如果存在的话。 如果这些时间匹配,则
签名存储在 。交付 文件被认为是准确的。 如果文件以前
签名与新的预期签名不匹配,则必须重新派生该文件。

请注意,只要有关依赖文件的任何内容发生更改,就会重新派生文件。 在
特别要注意的是 任何 更改受抚养人的修改时间(转发或
时间倒退)将强制重新编译派生文件。

使用这些签名是一种极其简单、高效、有效的方法
显着提高系统的再现性。

我们将用一个简单的例子来证明这一点:

# 简单的“你好,世界!” 构建文件
$CFLAGS = '-g' if $ARG{DEBUG} eq 'on';
$CONS = 新的缺点(CFLAGS => $CFLAGS);
程序 $CONS 'hello', 'hello.c';

注意 Cons 如何在适当的时间重新编译:

% 缺点 你好
cc -c 你好.c -o 你好.o
cc -o 你好你好.o
% 缺点 你好
缺点:“你好”是最新的。
% cons DEBUG=on 你好
cc -g -c 你好.c -o 你好.o
cc -o 你好你好.o
% cons DEBUG=on 你好
缺点:“你好”是最新的。
% 缺点 你好
cc -c 你好.c -o 你好.o
cc -o 你好你好.o

代码


许多软件开发组织将拥有一个或多个中央存储库目录
包含一个或多个项目的当前源代码的树,以及派生的
目标文件、库和可执行文件。 为了减少不必要的重新编译,
使用存储库中的文件来构建开发软件是很有用的——假设,
当然,本地构建树中不存在更新的依赖文件。

存储库

Cons 提供了一种机制来指定将被搜索的代码库列表,
按顺序,用于在本地构建目录树中找不到的源文件和派生文件。

以下几行在 建设 文件将指示 Cons 首先查看
/usr/experiment/存储库 目录,然后在 /usr/产品/存储库 目录:

存储库 qw (
/usr/experiment/存储库
/usr/产品/存储库
);

指定的存储库目录可能包含源文件、派生文件(对象、
库和可执行文件),或两者兼而有之。 如果下没有本地文件(源或派生)
执行 Cons 的目录,然后找到同名文件的第一个副本
在存储库目录下将用于构建任何本地派生文件。

Cons 维护一个存储库目录的全局列表。 缺点将消除
列表中的当前目录和任何不存在的目录。

查找 建设 文件 in a 存储库

缺点也会搜索 建设征募 存储库树中的文件。
但是,这会导致鸡与蛋的情况:您如何查看存储库树
查阅 建设 文件,如果 建设 文件告诉你存储库在哪里? 要得到
围绕这一点,可以通过命令行上的“-R”选项指定存储库:

% 缺点 -R /usr/experiment/repository -R /usr/product/repository 。

中指定的任何存储库目录 建设 or 征募 文件将被附加
到命令行“-R”选项指定的存储库目录。

存储库 资源

如果源代码(包括 征募 文件)的库版本 你好,
世界! C 应用程序位于存储库中(没有派生文件),Cons 将使用
用于创建本地目标文件和可执行文件的存储库源文件:

% cons -R /usr/src_only/repository 你好
gcc -c /usr/src_only/repository/hello.c -o hello.o
gcc -c /usr/src_only/repository/world.c -o world.o
a r libworld.a world.o
ar:创建 libworld.a
ranlib libworld.a
gcc -o 你好你好.o libworld.a

创建本地源文件将导致 Cons 重建适当的派生文件或
文件:

% 微微世界.c
[编辑]
% cons -R /usr/src_only/repository 你好
gcc -c 世界.c -o 世界.o
a r libworld.a world.o
ar:创建 libworld.a
ranlib libworld.a
gcc -o 你好你好.o libworld.a

并删除本地源文件将导致 Cons 恢复到构建派生
来自存储库源的文件:

% rm world.c
% cons -R /usr/src_only/repository 你好
gcc -c /usr/src_only/repository/world.c -o world.o
a r libworld.a world.o
ar:创建 libworld.a
ranlib libworld.a
gcc -o 你好你好.o libworld.a

存储库 衍生

如果存储库树包含派生文件(通常是目标文件、库或
可执行文件),Cons 将执行其正常的签名计算来决定是否
存储库文件是最新的,或者必须在本地构建派生文件。 这意味着,
为了确保正确的签名计算,存储库树还必须包含
。交付 Cons 在生成派生文件时创建的文件。

这通常是通过在存储库中构建软件来实现的(或者,
或者,在构建目录中,然后将结果复制到存储库中):

% cd /usr/所有/存储库
% 缺点 你好
gcc -c 你好.c -o 你好.o
gcc -c 世界.c -o 世界.o
a r libworld.a world.o
ar:创建 libworld.a
ranlib libworld.a
gcc -o 你好你好.o libworld.a

(这是安全的,即使 建设 文件列出了 /usr/all/存储库 目录中的
`Repository' 命令,因为 Cons 将从存储库中删除当前目录
列表。)

现在,如果我们想用我们自己的应用程序构建一个副本 你好ç 文件,我们只需要
创建一个必要的源文件,并使用“-R”选项让 Cons 使用其他
来自存储库的文件:

% mkdir $HOME/build1
% cd $HOME/build1
% 编辑 hello.c
[编辑]
% cons -R /usr/all/repository 你好
gcc -c 你好.c -o 你好.o
gcc -o 你好你好.o /usr/all/repository/libworld.a

请注意, Cons 并没有费心重新创建本地 libworld.a 库(或重新编译
世界.o 模块),而是使用存储库中已经编译的版本。

因为 Cons 放入的 MD5 签名 。交付 文件包含时间戳
派生文件,签名时间戳必须与签名的文件时间戳匹配
被视为有效。

一些软件系统可能会改变存储库文件的时间戳(通过复制它们,
例如),在这种情况下,Cons 将默认假设存储库签名无效
并不必要地重建文件。 可以通过指定以下内容来更改此行为:

Repository_Sig_Times_OK 0;

这告诉 Cons 在决定签名是否有效时忽略时间戳。 (笔记
避免这种健全性检查意味着必须对存储库进行适当的控制
树以确保派生文件不能在不更新的情况下被修改 。交付
签名。)

本地品牌 副本 of

如果存储库树包含构建的完整结果,并且我们尝试从构建
本地树中没有任何文件的存储库,有点令人惊讶
发生:

% mkdir $HOME/build2
% cd $HOME/build2
% cons -R /usr/all/repository 你好
缺点:“你好”是最新的。

为什么 Cons 说 hello 程序是最新的,当没有 hello 程序
本地构建目录? 因为存储库(不是本地目录)包含
跟上时代的 hello 程序,并且 Cons 正确地确定不需要做任何事情
重建这个文件的最新副本。

然而,在很多时候确保本地副本是适当的
文件始终存在。 例如,打包或测试脚本可能假定某些
生成的文件存在于本地。 而不是让这些附属脚本知道
存储库目录,可以将“本地”命令添加到 建设 or 征募 文件以
指定某个或多个文件必须出现在本地构建目录中:

本地 qw(
hello
);

然后,如果我们重新运行相同的命令,Cons 将从
存储库副本(告诉您它正在这样做):

% cons -R /usr/all/repository 你好
来自 /usr/all/repository/hello 的 hello 本地副本
缺点:“你好”是最新的。

请注意,因为制作本地副本的行为不被视为“构建”
hello 文件,缺点仍然报告它是最新的。

创建本地副本对于正在安装到
中间目录(用于与其他目录共享)通过“安装”命令。
将文件的“安装”命令与“本地”命令一起使用是这样的
Cons 提供了一个“Install_Local”命令作为一种方便的方法来执行这两个操作,这一点很常见:

Install_Local $env, '#export', 'hello';

完全等同于:

安装 $env '#export', 'hello';
本地 '#export/hello';

“Local”和“Install_Local”命令都更新本地 。交付 与该文件
适当的文件签名,以便将来正确执行构建。

存储库 依赖 分析

由于其内置扫描,Cons 将在指定的存储库树中搜索包含的
.h 文件。 除非编译器也知道存储库树,否则它将是
找不到 .h 仅存在于存储库中的文件。 例如,如果 你好ç
文件包括 你好.h 文件在其当前目录:

% cons -R /usr/all/repository 你好
gcc -c /usr/all/repository/hello.c -o hello.o
/usr/all/repository/hello.c:1: hello.h: 没有那个文件或目录

解决这个问题对构建环境的方式提出了一些要求
定义并介绍了 C `#include' 预处理器指令用于包含文件的方式。

为了通知编译器有关存储库树的信息,Cons 将添加适当的“-I”
编译命令的标志。 这意味着“CPPPATH”变量在
构造环境必须明确指定要搜索的所有子目录
对于包含的文件,包括当前目录。 因此,我们可以解决上述问题
例如通过更改环境创建 建设 文件如下:

$env = 新的缺点(
CC => 'gcc',
CPPPATH => '.',
LIBS => 'libworld.a',
);

由于`CPPPATH'变量的定义,当我们重新执行
命令:

% cons -R /usr/all/repository 你好
gcc -c -I。 -I/usr/all/repository /usr/all/repository/hello.c -o hello.o
gcc -o 你好你好.o /usr/all/repository/libworld.a

“-I”标志的顺序为 C 预处理器复制了相同的存储库-
Cons 用于其自身依赖性分析的目录搜索路径。 如果有
多个存储库和多个“CPPPATH”目录,Cons 将附加存储库
目录到每个`CPPPATH'目录的开头,数量迅速增加
'-I' 标志。 作为一个极端的例子,一个 建设 文件包含:

存储库 qw(
/u1
/u2
);

$env = 新的缺点(
CPPPATH => 'a:b:c',
);

将产生以下编译命令:

cc -Ia -I/u1/a -I/u2/a -Ib -I/u1/b -I/u2/b -Ic -I/u1/c -I/u2/c -c hello.c -o你好o

因为 Cons 依赖编译器的“-I”标志来传达顺序
必须搜索存储库目录,Cons 对存储库目录的处理是
与在 C 中的“#include”指令上使用双引号从根本上不兼容
源代码:

#include "file.h" /* 不要像这样使用双引号 */

这是因为大多数 C 预处理器在面对这样的指令时,总是首先
搜索包含源文件的目录。 这破坏了精心设计的“-I”
Cons 构造的选项以使预处理器符合其首选搜索
路径。

因此,当在 Cons 中使用存储库树时, 时刻 使用尖括号包含
文件:

#包括/* 使用角括号代替 */

资料库列表

Cons 提供了一个“Repository_List”命令来返回所有存储库目录的列表
按照他们当前的搜索顺序。 这可以用于调试,或者做更复杂的 Perl
东西:

@list = 存储库列表;
print join(' ', @list), "\n";

存储库 相互作用 other 缺点 功能

Cons 对存储库树的处理与其他 Cons 功能正确交互——这是
也就是说,它通常会按照您的预期进行。

最值得注意的是,存储库树与“链接”进行了正确且相当强大的交互
命令。 存储库树可能包含一个或多个用于版本构建的子目录
通过“链接”建立到源子目录。 缺点将搜索派生文件
存储库树下的适当构建子目录。

默认 目标


到目前为止,我们已经演示了使用显式目标来调用 Cons 来构建:

% 缺点 你好

通常,除非指定了目标,否则 Cons 不会构建任何东西,而是指定 '.'
(当前目录)将构建所有内容:

% cons # 不构建任何东西

% 缺点。 # 构建顶级目录下的所有内容

将“默认”方法添加到任何 建设 or 征募 文件将添加指定的
目标到默认目标列表。 如果没有,则缺点将构建这些默认值
在命令行中指定的目标。 所以将以下行添加到顶级
建设 默认情况下,文件将模仿 Make 构建所有内容的典型行为:

默认 '。';

以下将添加 hello 再见 命令(在与
建设 or 征募 文件)到默认列表:

默认 qw(
hello
再见
);

可以多次使用“默认”方法将目标添加到默认列表中。

可选择的 建立


Cons 提供了两种减少给定构建大小的方法。 第一种是通过指定
命令行上的目标,第二个是修剪构建树的方法。 好
首先考虑目标规格。

可选择的 瞄准

和 make 一样,Cons 允许在命令行中指定“目标”。 缺点目标
可以是文件或目录。 当指定目录时,这只是一个简短的
每个可衍生产品的手写符号——Cons 知道——在指定的
目录及以下。 例如:

% 缺点 build/hello/hello.o

意味着建造 你好 以及一切 你好 可能需要。 这是从以前的
的版本 你好, 世界! 其中的程序 你好 取决于
出口/包括/world.h. 如果该文件不是最新的(因为有人修改了
源代码/世界/世界.h),那么它将被重建,即使它位于远程目录中
构建/你好.

在这个例子中:

% 缺点构建

一切都在 建立 必要时建立目录。 同样,这可能会导致更多文件
待建。 特别是,两者 出口/包括/world.h导出/lib/libworld.a ,那恭喜你,
要求 构建/你好 目录,因此如果它们已过时,它们将被构建。

如果我们这样做,而是:

% 缺点出口

那么只有应该安装在导出目录中的文件才会被重建,如果
需要,然后安装在那里。 请注意,`cons build' 可能会构建`cons
export' 不建立,反之亦然。

没有 「特别」 目标

使用 Cons,不需要 make 风格的“特殊”目标。 带有缺点的最简单的模拟
是使用特殊 出口 目录,而不是。 例如,让我们假设您有一个
与您的代码相关联的整个单元测试系列。 测试生活在
代码附近的源目录。 但是,通常情况下,您不想构建这些测试。
一种解决方案是提供用于创建测试的所有构建说明,然后
将测试安装到树的一个单独部分。 如果我们将测试安装在顶级
目录称为 测试, 然后继续下面的操作:

% 缺点测试

将构建所有测试。

% 缺点出口

将构建系统的生产版本(但不是测试),并且:

% 缺点构建

可能应该避免(因为它会不必要地编译测试)。

如果您只想构建一个测试,那么您可以显式命名该测试(在
无论是 测试 目录或 建立 目录)。 您还可以汇总测试
进入测试目录中的一个方便的层次结构。 这种层次结构不需要
必须与源层次结构匹配,与包含层次结构的方式大致相同
可能与源层次结构不匹配(包含层次结构不太可能更多
比两个级别深,对于 C 程序)。

如果您想完全构建树中的所有内容(取决于您的任何选项)
选择),您可以使用:

% 缺点。

这不是特别有效,因为它会冗余地遍历所有的树,
包括源树。 当然,源树中可能有可构建的对象
它——没有什么能阻止你这样做,即使你通常在一个单独的构建中构建
树。

建立 修剪


结合目标选择, 建立 修剪 可以用来缩小范围
建造。 在前面的 peAcH 和 baNaNa 示例中,我们已经看到了脚本驱动
构建修剪可用于使任何给定的潜在构建仅可用的一半
调用`cons'。 Cons 还提供了一个方便的命令行约定
允许您指定哪个 征募 文件实际上是“构建”的——也就是说,被合并
进入构建树。 例如:

% 缺点构建 +world

`+' 参数引入了一个 Perl 正则表达式。 当然,这必须引用在
如果表达式中有任何 shell 元字符,则为 shell 级别。 这
表达式与每个匹配 征募 在“构建”中提到的文件
语句,并且只有那些具有匹配名称的脚本才真正合并到
建树。 允许多个这样的参数,在这种情况下,匹配任何一个
足以导致包含脚本。

在上面的例子中, hello 程序将不会被构建,因为 Cons 将没有
剧本知识 你好/应征者。 该 libworld.a 存档将被构建,但是,如果
需要。

通过命令行进行构建修剪有多种用途。 也许最有用
是进行本地更改的能力,然后,在充分了解
这些更改的后果,限制构建树的大小以加快速度
重建时间。 构建修剪的第二个用途是主动防止重新编译
您知道的某些文件将由于例如修改的头文件而重新编译。
您可能知道对头文件的更改是无关紧要的,或者
出于测试目的,可以安全地忽略大部分树的更改。
的观点是承认这种行为是务实的,并理解为
在下一次完整构建中,需要重建的一切都将是。 没有等价物
使用“make touch”命令,将文件标记为永久最新。 所以任何风险
减轻了构建修剪所产生的影响。 对于发布质量的工作,显然,我们建议
您不使用构建修剪(在集成期间使用完全可以,但是,
用于检查编译等。请确保在提交之前进行不受约束的构建
整合)。

临时 覆盖


Cons 提供了一种非常简单的机制来覆盖构建的各个方面。 本质是
您编写了一个包含一个或多个“覆盖”命令的覆盖文件,并且您
当你运行 `cons' 时,在命令行指定它:

% cons -o 过度出口

将建立 出口 目录,所有派生文件都受当前覆盖的影响
,在 超过 文件。 如果你省略了 `-o' 选项,那么所有需要删除的东西
所有覆盖将被重建。

覆写 环境 变量

覆盖文件可以包含两种类型的覆盖。 首先是传入环境
变量。 这些通常可以通过 建设 来自“%ENV”哈希的文件
多变的。 这些可以在覆盖文件中通过设置
'%ENV' 的适当元素(这些也可以在用户环境中被覆盖,
当然)。

覆盖 命令

第二种覆盖是通过 `Override' 命令完成的,它看起来像
这个:

覆盖, => , => , ...;

正则表达式 正则表达式 与作为候选的每个派生文件匹配
为构建。 如果派生文件匹配,则变量/值对用于
覆盖与派生文件关联的构造环境中的值。

假设我们有一个这样的构建环境:

$CONS = 新的缺点(
COPT => '',
CDBG => '-g',
CFLAGS => '%COPT %CDBG',
);

那么如果我们有一个覆盖文件 超过 包含此命令:

覆盖 '\.o$', COPT => '-O', CDBG => '';

然后任何使用 `-o over' 的 `cons' 调用创建 .o 通过此环境的文件将
导致它们用‘-O’而不是‘-g’编译。 当然,覆盖可以是
通过适当选择正则表达式限制在单个目录中。

这是 Hello, World! 的原始版本。 程序,在此环境下构建。
请注意,当应用或删除覆盖时,Cons 会重建适当的部分:

% 缺点 你好
cc -g -c 你好.c -o 你好.o
cc -o 你好你好.o
% 缺点 -o 超过你好
cc -O -c 你好.c -o 你好.o
cc -o 你好你好.o
% 缺点 -o 超过你好
缺点:“你好”是最新的。
% 缺点 你好
cc -g -c 你好.c -o 你好.o
cc -o 你好你好.o

重要的是,“覆盖”命令仅用于临时的、即时的
开发所需的覆盖,因为覆盖不是平台独立的,并且
因为他们过于依赖对脚本运作的深入了解。 为了
临时使用,但是,它们正是您想要的。

请注意,提供创建完全优化的功能仍然很有用
用于生产的系统版本——来自 建设征募 文件。 这边走
您可以根据平台定制优化的系统。 优化器权衡需要在哪里
制作(例如,特定文件可能无法完全优化编译),然后
这些可以直接记录在脚本中以供后代(和再现性)使用。

更多 on 施工 环境中


默认 施工 变量

我们已经提到并使用了一个概念 施工 环境,多次在
前几页。 现在是时候让这个更具体一点了。 与以下
声明:

$env = 新的缺点();

创建了对新的默认构造环境的引用。 这包含一个数字
构造变量和一些方法。 在目前的写作中,默认列表
构造变量定义如下:

抄送 => '抄送',
CFLAGS => '',
CCCOM => '%CC %CFLAGS %_IFLAGS -c %< -o %>',
INCDIRPREFIX => '-I',
CXX => '%CC',
CXXFLAGS => '%CFLAGS',
CXXCOM => '%CXX %CXXFLAGS %_IFLAGS -c %< -o %>',
链接 => '%CXX',
LINKCOM => '%LINK %LDFLAGS -o %> %< %_LDIRS %LIBS',
LINKMODULECOM => '%LD -r -o %> %<',
LIBDIRPREFIX => '-L',
AR => 'ar',
ARFLAGS => 'r',
ARCOM => "%AR %ARFLAGS %> %<\n%RANLIB %>",
RANLIB => 'ranlib',
AS => 'as',
ASFLAGS => '',
ASCOM => '%AS %ASFLAGS %< -o %>',
LD => 'ld',
LDFLAGS => '',
PREFLIB => 'lib',
SUFLIB => '.a',
SUFLIBS => '.so:.a',
SUFOBJ => '.o',
ENV => { '路径' => '/箱:/ usr / bin' },

在 Win32 系统 (Windows NT) 上,以下构造变量在
默认情况下:

CC => 'cl',
CFLAGS => '/nologo',
CCCOM => '%CC %CFLAGS %_IFLAGS /c %</Fo%>',
CXXCOM => '%CXX %CXXFLAGS %_IFLAGS /c %< /Fo%>',
INCDIRPREFIX => '/I',
链接 => '链接',
LINKCOM => '%LINK %LDFLAGS /out:%> %< %_LDIRS %LIBS',
LINKMODULECOM => '%LD /r /o %> %<',
LIBDIRPREFIX => '/LIBPATH:',
AR => 'lib',
ARFLAGS => '/nologo ',
ARCOM => "%AR %ARFLAGS /out:%> %<",
RANLIB => '',
LD => '链接',
LDFLAGS => '/nologo ',
预设 => '',
SUFEXE => '.exe',
SUFLIB => '.lib',
SUFLIBS => '.dll:.lib',
SUFOBJ => '.obj',

这些变量由与环境相关的各种方法使用,在
特别是最终调用外部命令的任何方法都将替代这些
变量到最后的命令,视情况而定。 例如,`Objects' 方法需要
一些源文件并安排派生,如有必要,相应的对象
文件。 例如:

对象 $env 'foo.c', 'bar.c';

如有必要,这将安排生产, foo.o酒吧. 调用的命令很简单
`%CCCOM',通过替换扩展为所需的适当外部命令
构建每个对象。 我们将在“命令”下进一步探索替换规则
方法,如下。

构造变量也用于其他目的。 例如,`CPPPATH' 是
用于指定包含目录的冒号分隔路径。 这些旨在成为
传递给 C 预处理器,也被 C 文件扫描机制用于
确定 C 编译中涉及的依赖项。 变量以
下划线,由各种方法创建,通常应视为“内部”
变量。 例如,当调用一个需要创建对象的方法时
从 C 源代码中,创建了变量“_IFLAGS”:这对应于“-I”开关
C 编译器要求表示由`CPPPATH' 指定的目录。

请注意,对于任何特定环境,变量的值设置一次,然后
从不重置(要更改变量,您必须创建一个新环境。提供了方法
用于为此目的复制现有环境)。 一些内部变量,例如
`_IFLAGS' 是按需创建的,但一旦设置,它们将在整个生命周期内保持不变
环境。

`CFLAGS'、`LDFLAGS' 和 `ARFLAGS' 变量都提供了一个将选项传递给的地方
分别是编译器、加载器和归档器。 不太明显,“INCDIRPREFIX”
变量指定要附加到每个包含开头的选项字符串
目录,以便编译器知道在哪里可以找到 .h 文件。 同样,
`LIBDIRPREFIX' 变量指定要附加到开头的选项字符串
链接器应搜索库的每个目录。

另一个变量“ENV”用于确定执行过程中的系统环境
的外部命令。 默认情况下,设置的唯一环境变量是“PATH”,
这是 UNIX 命令的执行路径。 为了获得最大的可重复性,您应该
真正安排在你的顶层设置你自己的执行路径 建设 文件(或
也许通过使用 Perl 的“use”命令导入适当的构造包)。 这
默认变量旨在让您起步。

插值 施工 变量

可以在源文件名和目标文件名中插入构造环境变量
通过在构造变量名称前加上“%”。

$env = 新的缺点(
DESTDIR => '程序',
SRCDIR => 'src',
);
程序 $env '%DESTDIR/hello', '%SRCDIR/hello.c';

构造变量的展开是递归的——即文件 姓名(s) 将被重新
扩展到无法进行更多替换。 如果构造变量不是
在环境中定义,则空字符串将被替换。

默认 施工 方法


默认构造方法列表包括以下内容:

'新' 构造函数

`new' 方法是一个 Perl 对象构造函数。 也就是说,它不是通过引用调用的
到现有的施工环境 参考,但是,而是静态地,使用名称
Perl 的 定义构造函数的地方。 该方法是这样调用的:

$env = 新的缺点( );

你得到的环境被加到了 `cons' 包中,这意味着它会
已经与下面描述的默认方法相关联。 个性化施工
可以通过在覆盖列表中提供名称/值对来覆盖变量。 注意
要覆盖任何命令环境变量(即“ENV”下的任何内容),您必须
覆盖所有这些。 您可以通过在
现有施工环境。

“克隆” 方法

`clone' 方法创建一个现有构建环境的克隆,并且可以
如下例所示:

$env2 = $env1->克隆( );

您可以以通常的方式提供覆盖以创建与
原来的。 如果您只想为相同的环境取一个新名称(这在以下情况下可能会有所帮助)
将环境导出到现有组件),您可以只使用简单的分配。

‘复制’ 方法

`copy' 方法从外部定义的构造变量中提取
环境并将它们作为名称/值对列表返回。 覆盖也可以
提供,在这种情况下,将酌情返回覆盖的值。 这
返回的列表可以分配给一个散列,如下面的原型所示,但它也可以
以其他方式操纵:

%env = $env1->copy( );

‘ENV’的值,它本身就是一个散列,也被复制到一个新的散列中,所以这可能是
改变了就不怕影响原来的环境。 所以,例如,如果你真的
只想覆盖默认环境中的“PATH”变量,您可以执行
在以下:

%cons = new cons()->copy();
$cons{ENV}{PATH} = " ”;
$cons = 新的缺点(%cons);

这将保留默认执行环境中可能存在的任何其他内容
不受干扰。

‘安装’ 方法

`Install' 方法安排指定的文件安装在指定的
目录。 安装优化:如果可以链接,则不复制文件。 如果
这不是所需的行为,您将需要使用不同的方法来安装
文件。 它被称为如下:

安装 $env , ;

请注意,虽然要安装的文件可以任意命名,但只有最后一个
每个名称的组件用于安装的目标名称。 所以,例如,如果你
安排安装 富/酒吧 in 巴兹,这将创建一个 酒吧 文件中 巴兹 目录(不是
富/酒吧).

‘安装为’ 方法

`InstallAs' 方法安排指定的源 文件(s) 安装为
指定目标 文件(s). 应将多个文件指定为文件列表。 这
安装优化:如果可以链接,则不复制文件。 如果这不是
所需的行为,您将需要使用不同的方法来安装文件。 这是
调用如下:

`InstallAs' 有两种工作方式:

单文件安装:

InstallAs $env TgtFile, SrcFile;

多文件安装:

InstallAs $env ['tgt1', 'tgt2'], ['src1', 'src2'];

或者,即使是:

@srcs = qw(src1 src2 src3);
@tgts = qw(tgt1 tgt2 tgt3);
安装为 $env [@tgts], [@srcs];

目标列表和源列表的长度应该相同。

'珍贵' 方法

`Precious' 方法要求 cons 在删除之前不要删除指定的文件或文件列表
再次建造它们。 它被调用为:

宝贵的;

这对于允许对库进行增量更新或调试特别有用
每次都更新而不是重新构建的信息文件。 缺点还是会
指定`-r' 标志时删除文件。

'命令' 方法

`Command' 方法是一种包罗万象的方法,可用于安排任何外部
要调用的命令来更新目标。 对于此命令,目标文件和列表
提供输入。 此外,还提供了一个或多个构造命令行作为
字符串(这个字符串中可能嵌入了多个命令,用 new 分隔
行)。 “命令”的调用方式如下:

命令 $env , , ;

目标取决于指定的输入文件列表,并且输入必须
成功构建,否则 Cons 将不会尝试构建目标。

在构造命令中,来自构造环境的任何变量都可以是
通过在构造变量的名称前加上“%”来引入。 这是递归的:
该命令被扩展,直到不能进行更多的替换。 如果一个建筑
环境中未定义变量,则将替换空字符串。 一种
在构造命令中,双倍的“%%”将被替换为单个“%”。

有几个伪变量也将被扩展:

%> 目标文件名(在多目标命令中,这始终是第一个目标
提及)。

%0 与 `%>' 相同。

%1,%2,...,%9
这些分别指第一个到第九个输入文件。

%< 完整的输入集。 如果这些中的任何一个已经在其他任何地方使用过
当前命令行(通过“%1”、“%2”等),然后这些将从
'%<' 提供的列表。 考虑在一个 征募 文件
,在 test 目录:

命令 $env 'tgt', qw(foo bar baz), qq(
回声 %< -i %1 > %>
回声 %< -i %2 >> %>
回声 %< -i %3 >> %>
);

If 时间 需要更新,那么这将导致执行
以下命令,假设尚未为 test
目录:

echo test/bar test/baz -i test/foo > test/tgt
echo test/foo test/baz -i test/bar >> test/tgt
echo test/foo test/bar -i test/baz >> test/tgt

上面的任何伪变量都可以紧跟以下之一
选择扩展路径名的一部分的后缀:

:a 文件名的绝对路径
:b 目录加上去掉任何后缀的文件名
:d 目录
:f 文件名
:s 文件名后缀
:F 去掉任何后缀的文件名

继续上面的例子,`%<:f' 会扩展为 `foo bar baz',而 `%':d> 会
扩展为“测试”。

可以通过包含部分命令以编程方式重写命令的一部分
'%[' 和 '%]' 之间。 这将调用命名为第一个单词的构造变量
括在括号中作为 Perl 代码参考; 将使用此调用的结果
替换命令行中括号的内容。 例如,给定一个
现有的输入文件命名 输入文件:

@keywords = qw(foo bar baz);
$env = new cons(X_COMMA => sub { join(",", @_) });
命令 $env 'tgt', 'tgt.in', qq(
echo '# 关键字:%[X_COMMA @keywords %]' > %>
猫%< >> %>
);

这将执行:

echo '# 关键字:foo,bar,baz' > tgt
猫 tgt.in >> tgt

替换发生后,空格字符串被转换为单个空格,并且
消除了前导和尾随空格。 因此无法引入
传递给命令的字符串中的可变长度空白,不诉诸某些
某种外壳引用。

如果提供了多行命令字符串,则命令按顺序执行。 如果有的话
的命令失败,然后不执行其余的命令,并且目标未标记为
更新,即不为目标存储新签名。

通常,如果所有命令都成功,并返回零状态(或任何平台-
需要特定的成功指示),然后存储一个新的签名
目标。 如果命令在失败后错误地报告成功,那么 Cons 将
假设该命令创建的目标文件是准确的和最新的。

每个命令字符串的第一个字,在扩展后,被假定为一个可执行文件
命令在 `PATH' 环境变量上查找(反过来,它由
“ENV”构造变量)。 如果在路径上找到此命令,则目标将
取决于它:因此,命令将根据需要自动构建。 它是
可以将多部分命令写入一些 shell,用分号分隔。 只有
然而,第一个命令词将取决于,所以如果你写你的命令字符串
这样,您必须显式地设置依赖项(使用 `Depends' 方法),或者
确保您使用的命令是一个系统命令
可用的。 如果它不可用,您当然会收到错误消息。

如果任何命令(即使是多行命令中的一个)以 `[perl]' 开头,其余的
该命令行的代码将由正在运行的 Perl 进行评估,而不是由
壳。 如果在解析 Perl 时发生错误或 Perl 表达式返回 0 或
undef,该命令将被视为失败。 例如,这里有一个简单的
直接从 Perl 创建文件 `foo' 的命令:

$env = 新的缺点();
命令 $env 'foo',
qq([perl] open(FOO,'>foo');print FOO "hi\\n"; close(FOO); 1);

请注意,当命令执行时,您与执行时在同一个包中 建设
or 征募 文件被读取,所以你可以调用你在同一个文件中定义的 Perl 函数
建设 or 征募 出现“命令”的文件:

$env = 新的缺点();
子创建文件{
我的 $file = shift;
打开(文件,“>$文件”);
打印文件 "hi\n";
关闭(文件);
1返回;
}
命令 $env 'foo', "[perl] &create_file('%>')";

Perl 字符串将用于生成派生文件的签名,因此如果您
更改字符串,文件将被重建。 您调用的任何子程序的内容,
然而,不是签名的一部分,所以如果你修改一个被调用的子程序,比如
上面的`create_file',目标将 不能 被重建。 警告用户。

Cons 通常在执行之前打印命令。 如果
命令的第一个字符是`@'。 请注意,您可能需要将 `@' 与
命令名称或将其转义以防止 `@cmd' 看起来像 Perl 引用的数组
执行插值的运算符:

# 第一个命令行不正确,
# 因为“@cp”看起来像一个数组
# 到 Perl qq// 函数。
# 改用第二种形式。
命令 $env 'foo', 'foo.in', qq(
@cp %< 临时文件
@cp 临时文件 %>
);

如果扩展命令行中的任何地方都有 shell 元字符,例如 `<',
`>'、引号或分号,那么命令将通过调用
壳。 这意味着一个命令,例如:

光盘

单独通常会失败,因为路径上没有命令“cd”。 但是命令
串:

cd $<:d; 焦油 cf $>:f $<:f

展开时仍将包含外壳元字符分号,外壳将是
调用来解释命令。 由于“cd”由这个子shell解释,命令
将按预期执行。

要指定具有多个目标的命令,您可以指定对列表的引用
目标。 在 Perl 中,可以通过将列表括在方括号中来创建列表引用。
因此,以下命令:

命令 $env ['foo.h', 'foo.c'], 'foo.template', q(
第 %1 代
);

可以在命令 `gen' 创建两个文件的情况下使用 foo.hfoo.c.

'对象' 方法

`Objects' 方法安排创建对应于指定的目标文件
源文件。 它的调用方式如下所示:

@files = 对象 $env ;

在 Unix 下,源文件以 .s.c 目前支持,将编译
以同一个文件名结尾 .o. 默认情况下,所有文件都是通过调用创建的
扩展“CCCOM”构造变量产生的外部命令,
`%<' 和 `%>' 分别设置为源文件和目标文件(参见 `Command' 方法
扩展细节)。 扫描源文件时也使用变量“CPPPATH”
对于依赖项。 这是一个以冒号分隔的路径名列表,也用于创建
构造变量`_IFLAGS',它将包含适当的-`I'列表
编译选项。 `CPPPATH' 中的任何相对路径名都是相对解释的
到创建关联构建环境的目录(绝对
也可以使用顶级相对名称)。 这个变量由`CCCOM'使用。 行为
可以通过更改任何插入的变量来修改此命令的
进入“CCCOM”,例如“CC”、“CFLAGS”,以及间接地“CPPPATH”。 也可以
替换“CCCOM”本身的值。 为方便起见,此文件返回以下列表
对象文件名。

'程序' 方法

`Program' 方法安排将指定的程序与指定的对象链接起来
文件。 它以下列方式调用:

程序 $env , ;

程序名称将附加“SUFEXE”构造变量的值(通过
默认,在 Win32 系统上为 `.exe',在 Unix 系统上没有)如果后缀还没有
当下。

可以指定源文件代替目标文件——`Objects' 方法将是
调用以安排所有文件到目标文件的转换,因此所有
上面关于“Objects”方法的观察也适用于这个方法。

程序的实际链接将由一个外部命令处理,该命令导致
从扩展“LINKCOM”构造变量,将“%<”设置为目标文件
被链接(按照显示的顺序),并将“%>”设置为目标(参见“Command”方法
扩展细节)。 用户可以在构造中设置额外的变量
环境,包括“LINK”,定义用于链接的程序,“LIBPATH”,一个
以冒号分隔的库搜索路径列表,用于
申请 -llib, 和 `LIBS',指定要链接的库列表(在任一 -llib
形式或只是作为路径名。 解释“LIBPATH”和“LIBS”中的相对路径名
相对于创建关联构建环境的目录
(也可以使用绝对和顶级相对名称)。 缺点自动设置
对“LIBS”中提到的任何库的依赖:这些库将在之前构建
该命令已链接。

“图书馆” 方法

`Library' 方法安排从指定的对象创建指定的库
文件。 它的调用方式如下:

图书馆 $env , ;

库名将附加“SUFLIB”构造变量的值(通过
默认,在 Win32 系统上为“.lib”,在 Unix 系统上为“.a”)如果后缀还没有
当下。

可以指定源文件代替目标文件——`Objects' 方法将是
调用以安排所有文件到目标文件的转换,因此所有
上面关于“Objects”方法的观察也适用于这个方法。

库的实际创建将由一个外部命令处理,该命令导致
从扩展“ARCOM”构造变量,将“%<”设置为库成员(在
显示的顺序),以及“%>”到要创建的库(参见“Command”方法)
扩展细节)。 用户可以在构建环境中设置变量
影响命令的运行。 这些包括“AR”,要使用的存档程序,
`ARFLAGS',可以用来修改给由`AR'指定的程序的标志,
和 `RANLIB',归档索引生成程序的名称,如果需要的话(如果特定的
需要不需要后一个功能,则必须重新定义“ARCOM”以不
参考'RANLIB')。

`Library' 方法允许在多个方法中指定相同的库
调用。 来自所有调用的所有贡献对象(可能来自
不同的目录)由单个归档命令组合和生成。 笔记,
但是,如果您修剪构建以便仅指定库的一部分,则仅
将生成库的那部分(其余部分将消失!)。

“模块” 方法

“模块”方法是“程序”和“命令”方法的组合。 而不是
直接生成可执行程序,这个命令允许你指定自己的
命令来实际生成一个模块。 该方法的调用方式如下:

模块 $env , , ;

此命令在您希望动态创建的情况下很有用
加载的模块或静态链接的代码库。

‘视情况而定’ 方法

`Depends' 方法允许您为目标指定额外的依赖项。 它是
调用如下:

取决于 $env , ;

这可能偶尔有用,尤其是在没有扫描仪存在(或
可写)用于特定类型的文件。 通常,计算依赖项
自动从方法设置的显式依赖项的组合
调用或通过扫描源文件。

可以使用对多个目标的引用来指定一组相同的依赖项
目标列表。 在 Perl 中,可以通过将列表括在正方形中来创建列表引用
括号。 因此,以下命令:

取决于 $env ['foo', 'bar'], 'input_file_1', 'input_file_2';

指定两个 FOO酒吧 文件取决于列出的输入文件。

‘忽略’ 方法

`Ignore' 方法允许您忽略 Cons 对其推断的显式依赖项
自己的。 它的调用方式如下:

忽略;

这可用于避免由于系统头文件或
已知不会影响生成的目标的实用程序。

例如,如果在多个系统上的 NFS 挂载目录中构建了一个程序,
有不同的副本 标准输出文件,差异将影响所有的签名
从`#include 的源文件构建的派生目标'。 这将导致所有
更改系统时要重建的那些目标。 如果这不是可取的行为,
那么以下行将删除对 标准输出文件 文件:

忽略 '^/usr/include/stdio\.h$';

请注意,`Ignore' 方法的参数是正则表达式,所以特殊
必须对字符进行转义,您可能希望锚定开头或结尾
带有“^”或“$”字符的表达式。

'盐' 方法

“Salt”方法为每个派生的签名计算添加一个常数值
文件。 它的调用方式如下:

盐 $string;

更改 Salt 值将强制完全重建每个派生文件。 这可以
用于在某些需要的情况下强制重建。 例如,

盐`uname -s`;

每当操作系统打开时,将强制完全重建每个派生文件
执行的构建(如`uname -s'报告)发生了变化。

'使用缓存' 方法

`UseCache' 方法指示 Cons 维护要共享的派生文件的缓存
在同一项目的不同构建树之间。

UseCache("缓存/ ") 监听警告("缓存目录未找到");

`源路径' 方法

`SourcePath' mathod 返回文件的真实源路径名,与
构建目录中的路径名。 它的调用方式如下:

$path = 源路径;

'ConsPath' 方法

如果提供的路径是可派生文件,则 `ConsPath' 方法返回 true,并返回
undef (false) 否则。 它的调用方式如下:

$result = ConsPath ;

'分割路径' 方法

`SplitPath' 方法在默认分隔的字符串中查找多个路径名
操作系统的路径分隔符(UNIX 系统上的“:”,Windows NT 上的“;”),以及
返回完全限定的名称。 它的调用方式如下:

@paths = SplitPath ;

`SplitPath' 方法会将前缀为 '#' 的名称转换为适当的顶级构建
名称(不带“#”)并将相对名称转换为顶级名称。

'方向路径' 方法

`DirPath' 方法返回构建路径 姓名(s) 目录或目录列表。
它的调用方式如下:

$cwd = 目录路径;

“DirPath”方法最常见的用途是:

$cwd = DirPath '.';

获取子公司当前目录的路径 征募 文件中。

'文件路径' 方法

`FilePath' 方法返回构建路径 姓名(s) 文件或文件列表。 它是
调用如下:

$file = 文件路径;

‘帮助’ 方法

`Help' 方法指定了当用户调用 `cons 时将显示的帮助文本
-H'。 这可用于提供特定目标、值、构建的文档
构建树的选项等。 它的调用方式如下:

帮助;

`Help' 方法只能被调用一次,并且通常应该在顶部指定
水平 建设 文件中。

扩展 缺点


覆写 施工 变量

有几种扩展 Cons 的方法,它们的难度各不相同。 最简单的
方法是定义自己的构建环境,基于默认环境,
但经过修改以反映您的特定需求。 这通常足以满足基于 C 的
应用程序。 您可以使用“new”构造函数以及“clone”和“copy”方法来
创建混合环境。 这些变化可以对底层完全透明
征募 文件。

添加 方法

对于稍微要求更高的更改,您可能希望在 `cons' 中添加新方法
包裹。 这是一个非常简单的扩展示例,“InstallScript”,它安装了一个
tcl 脚本在请求的位置,但首先编辑脚本以反映平台-
脚本中需要安装的依赖路径:

# cons::InstallScript - 创建一个依赖于平台的 shell 版本
# 将字符串“#!your-path-here”替换为特定平台的脚本
# 路径 $BIN_DIR。

子缺点::安装脚本{
我的 ($env, $dst, $src) = @_;
命令 $env $dst, $src, qq(
sed s+你的路径-这里+$BIN_DIR+ %< > %>
chmod oug+x %>
);
}

请注意,此方法是直接在 `cons' 包中定义的(通过在名称前加上前缀
带有`缺点​​::')。 以这种方式进行的更改将对所有环境全局可见,
并且可以在以下示例中调用:

InstallScript $env "$BIN/foo", "foo.tcl";

为了对一般性进行小幅改进,可以将“BINDIR”变量作为
参数或取自构建环境--作为`%BINDIR'。

覆写 方法

您可以定义一个新包,而不是将方法添加到 `cons' 名称空间
它从`cons'包继承现有方法并覆盖或添加其他方法。 这
可以使用 Perl 的继承机制来完成。

下面的例子定义了一个新的包`cons::switch',它覆盖了标准
“图书馆”方法。 重写的方法构建链接的库模块,而不是库
档案。 提供了一个新的构造函数。 使用此构造函数创建的环境将
拥有新的库方法; 其他人不会。

包缺点::开关;
开始 {@ISA = '缺点'}

子新{
转移;
祝福新的缺点(@_);
}

子库{
我的($env)= 转变;
我的($lib)= 转移;
my(@objs) = 对象 $env @_;
命令 $env $lib, @objs, q(
%LD -r %LDFLAGS %<-o %>
);
}

可以按以下示例调用此功能:

$env = 新缺点::switch(@overrides);
...
图书馆 $env 'lib.o', 'foo.c', 'bar.c';

调用中 缺点


`cons' 命令通常从构建树的根调用。 一个 建设 文件
必须存在于该目录中。 如果使用了 `-f' 参数,则替代 建设
可以使用文件(也可能使用备用根,因为 `cons' 将 cd 到 建设
文件的包含目录)。

如果使用 `-t' 参数从构建树根的子节点调用 `cons',它
将沿着目录层次结构向上查找 建设 文件。 (替代名称可以
仍然用`-f'指定。)命令行上提供的目标将被修改
相对于发现的 建设 文件。 例如,从包含
一个顶级 建设 文件,调用如下:

% cd libfoo/子目录
% cons -t 目标

完全等同于:

% 缺点 libfoo/subdir/target

如果在目录层次结构中指定了任何“默认”目标 建设 or
征募 文件,只有在 `cons -t' 所在目录或以下的默认目标
被调用将被构建。

调用命令如下:

缺点——

哪里 参数 可以是以下任何一种,以任何顺序:

目标 构建指定的目标。 如果 目标 是一个目录,然后递归构建
该目录中的所有内容。

+模式 限制 征募 只考虑匹配的文件 模式,这是
Perl 正则表达式。 接受多个“+”参数。

姓名=
套数 姓名 重视 VAL 在传递给顶层的“ARG”哈希中 建设 文件中。

`-cc' 显示在从缓存中检索时会执行的命令。 不
给出文件已被检索的指示; 这对
生成可以与真实构建日志进行比较的构建日志。

`-cd' 禁用所有缓存。 不要从缓存中检索,也不要刷新到缓存。

`-cr' 以随机顺序构建依赖项。 这在构建多个时很有用
启用缓存的类似树。

`-cs' 将发现是最新的现有构建目标与缓存同步。
如果使用 -cc 禁用缓存或最近才启用缓存,这将很有用
与 UseCache。

`-d' 启用依赖调试。

'-f'
使用指定的文件代替 建设 (但首先更改为包含
目录 文件).

`-h' 如果定义了这样的帮助信息,则显示当前构建的本地帮助信息,然后退出。

`-k' 出错后尽可能继续。

'-o'
读取覆盖文件 文件.

`-p' 在指定的树中显示建筑产品。 不尝试构建。

`-pa' 显示构建产品和相关操作。 不尝试构建。

`-pw' 显示产品及其定义位置。 不尝试构建。

`-q' 不要冗长安装和删除目标。

`-r' 删除与相关的构造产品. 不尝试构建。

'-R'
在中搜索文件 休息。 多 -R 休息 在目录中搜索
指定的顺序。

`-t' 向上遍历目录层次结构寻找 建设 文件,如果不存在
在当前目录中。 目标将被修改为相对于
建设 文件中。

`-v' 显示 `cons' 版本并继续处理。

`-V' 显示 `cons' 版本并退出。

'-wf'
将所有考虑的文件名写入 文件.

`-x' 显示与此类似的帮助信息,然后退出。

构造参数 可以是您希望在 建设 文件中。
注意应该有一个 -- 将 cons 的论点与您提出的论点分开
希望在处理 建设 文件中。

加工 构造参数 可以通过任何标准包来完成 获取选择 或其
变体,或任何用户定义的包。 缺点 将通过 构造参数 as @ARGV
不会试图解释任何事情之后 --.

% cons -R /usr/local/repository -d os=solaris +driver -- -c test -f DEBUG

将以下内容传递给缺点

-R /usr/local/repository -d os=solaris +驱动程序

以及以下,到顶层 建设 归档为 @ARGV

-c 测试 -f 调试

注意`cons -r .' 相当于一个完全递归的‘make clean’,但不需要
在支持 建设 文件或任何 征募 文件。 这是最有用的,如果你是
将文件编译到源目录中(如果将 建立出口 目录,
那么你可以删除目录)。

选项 `-p'、`-pa' 和 `-pw' 作为阅读的辅助工具非常有用
脚本或调试它们。 如果你想知道安装了什么脚本 导出/包含/foo.h,
例如,只需键入:

% 缺点 -pw 导出/包含/foo.h

运用 写作 依赖 扫描仪


QuickScan 允许为源文件设置简单的独立于目标的扫描仪。 仅有的
一个 QuickScan 扫描仪可以与任何给定的源文件和环境相关联。

QuickScan 的调用方式如下:

QuickScan CONSENV CODEREF,文件名 [,路径]

CODEREF 引用的子例程应返回包含的文件名列表
直接通过文件。 这些文件名将依次被扫描。 可选的 PATH 参数
提供查找 FILENAME 和/或用户提供的文件的查找路径
子程序。 PATH 可能是对查找目录名称数组的引用,或
由系统的分隔符分隔的名称字符串(在 UNIX 系统上为“:”,在 UNIX 系统上为“;”
视窗NT)。

该子例程为文件中的每一行调用一次,$_ 设置为当前行。
如果子程序需要查看额外的行,或者,就此而言,整个文件,
然后它可以自己从文件句柄 SCAN 读取它们。 它也可以终止循环,如果
通过关闭文件句柄,它知道没有进一步的包含信息可用。

无论是否提供查找路径,QuickScan 首先尝试查找文件
相对于当前目录(对于直接提供给 QuickScan 的顶级文件),
或从包含引用该文件的文件的目录。 这不是很
一般,但似乎足够好——尤其是如果你有机会自己写
实用程序,并且可以以标准方式控制搜索路径的使用。 最后,
目前,搜索路径以冒号分隔。 这可能不会让 NT 阵营高兴。

这是一个真实的例子,取自 建设 文件在这里:

子缺点::SMFgen {
我的($env,@tables)=@_;
foreach $t (@tables) {
$env->QuickScan(sub { /\b\S*?\.smf\b/g }, "$t.smf",
$env->{SMF_INCLUDE_PATH});
$env->命令(
["$t.smdb.cc","$t.smdb.h","$t.snmp.cc","$t.ami.cc", "$t.http.cc"],
"$t.smf",
q(
smfgen %( %SMF_INCLUDE_OPT %) %
)
);
}
}

[注意‘$env->QuickScan ...’和‘$env->Command ...’的形式不应该是
必要的,但出于某种原因,是此特定调用所必需的。 这出现
是 Perl 中的错误或我的误解; 这种调用方式不
似乎总是必要的。]

这将查找表单的所有名称.smf 文件中。 即使它会返回名称
它们可以在评论中找到,但这没关系(该机制允许额外的文件;
他们只是假设丢失的文件将被忽略,当
程序,在本例中,实际上是调用 smfgen)。

扫描器仅在给定的源文件被某些目标需要时才被调用
树。 对于给定的源文件,它只会被调用一次。

这是构建相同扫描仪的另一种方法。 这个使用显式代码引用,
并且(在这种情况下,不必要地)读取整个文件本身:

子我的扫描{
我的(@includes);
做 {
推(@includes, /\b\S*?\.smf\b/g);
} 尽管;
@包括
}

请注意,循环的顺序是相反的,最后是循环测试。 这是
因为第一行已经为你读过了。 此扫描仪可以连接到源
文件由:

快速扫描 $env \myscan, "$_.smf";

客户服务 AND 建议


缺点由用户社区维护。 要订阅,请发送邮件至 讨论-
[电子邮件保护] 与身体 订阅.

请通过以下方式报告任何建议 [电子邮件保护] 邮件列表。

使用 onworks.net 服务在线使用缺点


免费服务器和工作站

下载 Windows 和 Linux 应用程序

Linux 命令

Ad