首页 > 其他分享 >GNU Autotools Autoconf Automake Libtool[翻译]

GNU Autotools Autoconf Automake Libtool[翻译]

时间:2023-03-02 15:56:12浏览次数:71  
标签:configure GNU -- Makefile Automake 编译器 构建 Autoconf config

在编译可移植代码的时候,非常的困难,因为不同系统的编译工具版本可能不一样,类库路径不一样,头文件不一样,所以手动解决这些事情非常的痛苦,并且由于系统更新迭代太快,导致根本无法维护,GNU Autotool的出现就是为了解决这个事情。

GNU Autotool是GNU toolchain的一部分,GNU Build System使得在编译代码的时候变得非常简单,只需要运行configuremake

简介

GNU Autoconf

Autoconf根据configure.ac文件生成configure脚本。

configure运行的时候会创建一个config.status脚本文件,然后这个脚本根据Makefile.in文件创建Makefile文件。

最后运行make编译程序。

Autoconf是由几个辅助程序组成的:

  • autoheader--管理C语言的头文件
  • autoscan--创建初始化输入文件
  • ifnames--列出项目中C语言预处理定义

GNU Automake

Automake根据Makefile.am创建Makefile.in文件。Automake同样也实现依赖跟踪,每次源码编译的时候,依赖列表会被记录,当运行make的时候,如果发现依赖更改了,就会重新编译依赖文件。

GNU Libtool

Libtool用来管理在类Unix操作系统下创建静态库或者动态库。Libtool通过抽象化类的创建过程来屏蔽不同系统之间的区别。

开始配置

虽然autotool自动化实现了很多功能,但是使用autotool还是需要配置一些脚本

编写configure.in文件

autoconfig需要configure.in文件,autoconf的文档中说明了configure.in如何编写。

可以在configure.in中写测试函数用来检测不同系统的相关条件(比如一些头文件或者函数)是否发满足。

比如gettimeofday函数,并不是所有系统上都有,可以使用AC_CHECK_FUNCS(gettimeofday)进行判断,代码中使用HAVE_GETTIMEOFDAY进行区分。

autoscan可以检测代码的可移植性,用于配置测试功能。

ifnames可以列出所有的预处理判断语句,便于检测不同系统代码的编译问题。

configure.in中常用宏介绍:

AC_INIT

初始化方法,放在第一行

AC_PREREQ(VERSION)

可选,指定`autoconf`版本。`AC_PREREQ(2.12)`

AM_INIT_AUTOMAKE

使用`automake`需要设置这个宏,说明项目名称和版本。`AM_INIT_AUTOMAKE(foo, 1.0)`

AM_CONFIG_HEADER

指定在运行时需要的宏定义头文件(一般命名为`config.h`)。在代码中用`#include "config.h"`引入使用。默认情况下,工程中该文件名称为`config.h.in`,使用`AM_CONFIG_HEADER(config.h:config.h.in)`可以在代码中直接引用`config.h`
如果不使用`automake`,应该用`AC_CONFIG_HEADER`代替`AM_CONFIG_HEADER`

AM_MAINTAINER_MODE

这个宏一般出现在Cygnus的配置脚本中。其他的程序可能用到也可能用不到。如果这个宏使用了,需要增加`--enable-maintainer-mode`选项,用来启用在配置系统时的自动构建生成文件。如果这个宏没有使用,生成的文件每次都会自动构建。如果环境变量中使用的`autoconf` `automake`版本不对,就会产生问题。如果不使用`automake`,就不需要这个宏。

AC_PROG_CC

编译C代码工程时,这个宏会选择系统上的C编译器使用。如果是想交叉编译其他系统的代码,可能会有问题。

AC_PROG_CXX

与`AC_PROG_CC`作用一样,只不过是用于C++代码。

AM_PROG_LIBTOOL

使用libtool,编译一个用于共享的类库或者使用`libtool`链接库。默认情况下会把所有的库都编译成共享库,可以在`AM_PROG_LIBTOOL`前使用`AM_DISABLE_SHARED`来禁止。`--enable-shared`和`--disable-shared`会覆盖默认配置。

AC_OUTPUT

列出`configure`创建的文件列表,基本上都是Makefile文件,如果有子目录,也需要指定子目录的Makefile。`AC_OUTPUT(Makefile lib/Makefile)`,项目根目录创建一个Makefile,然后有一个lib目录,也要创建一个Makefile

如果在configure.in使用自己定义的宏,需要写一个acinclude.m4文件来定义这些宏(如果不使用automake,这个文件名需要改为aclocal.m4)。除此之外,也可以把宏放到m4的文件夹中,在Makefile.am中增加ACLOCAL_AMFLAGS = -I m4,运行aclocal就可以找到这些宏。

AC_开头的是autoconf的宏。AM_开头的是automake或者libtool的宏。

编写Makefile.am

automake的输入文件,官方文档有具体的说明。

Makefile.am中的automake的命令看起来很像Makefile中的变量赋值。automake识别特殊的规则,然后根据需要自动的添加到输出文件中。

项目中每个目录都应该有一个Makefile.am文件,对于每个包含子目录的目录,其Makefile.am需要包含
SUBDIRS = dir dir ...
每一个dir是子目录的名字。

对于每一个Makefile.am都应该在configure.inAC_OUTPUT中有对应的Makefile

构建程序

bin_PROGRAMS = program

program是程序名

program_SOURCES = file file ...

file是构建程序需要链接的源文件,program有上面的名称指定

构建非共享类库

lib_LIBRARIES = libname.a

libname.a是类库名称

libname_a_SOURCES = file file ...

file是构建类库需要的源文件。

构建共享类库

lib_LTLIBRARIES = libname.la

libname.la是类库名称

LTLIBRARIES.la后缀,表示使用libtool编译

libname_la_SOURCES = file file ...

file是构建共享库需要的源文件

bin_PROGRAMSlib_LIBRARIES中的binlib字段不是随便设置的,这些字段指明了一个目录,可以通过--bindir--libdirconfigure的时候设置。如果这些选项没有设置,那么就会使用--prefix或者--exec-prefix的配置。如果需要安装到其他目录,就需要设置为其他名称。

bin_PROGRAMS表示安装到前面配置时指定的目录,如果没有配置就是系统默认bin目录下

Makefile.am应该包含一个标准的Makefile文件所需要的所有内容。同样automake也支持其他特殊的变量,具体参考官方文档。

编写acconfig.h

如果你准备生成一个可移植性的头文件(比如在configure.in中使用AM_CONFIG_HEADER),需要编写acconfig.h文件,这个文件必须包含如下内容:

/* Name of package.  */
#undef PACKAGE

/* Version of package.  */
#undef VERSION

acconfig.h也为configure.in中不常用的以及出现在AC_DEFINE中的宏增加同样的#undef注释行。

如果编写GNU工程并且包含了AC_DEFINE(_GNU_SOURCE)configure.in中,那么需要在acconfig.h中增加如下内容:

/* Enable GNU extensions.  */
#undef _GNU_SOURCE

当在执行的时候autoheader会通过打印错误日志的方式把这些需求信息打印出来。如果你做了什么奇怪的事情在configure.in中,必须确保在acconfig.h有正确的条目,不然代码使用的config.h文件的测试结果可能是无效的。

如果不使用automakePACKAGEVERSION是不需要的,并且也不需要acconfig.h文件。

构造文件

编写完configure.in, Makefile.am, acconfig.h或者还有acinclude.m4后,就需要使用autoconfautomake来构建程序了:

  • aclocal
  • autoconf
  • autoheader
  • automake

aclocalautomake命令是automake包中的内容,autoconfautoheader命令是autoconf包中的内容。

如果使用了m4目录,那么需要在运行aclocal的指定-I m4

如果不使用Cygnus,那么在运行automake的时候增加-a来把需要的文件拷贝到自己的源码目录。

如果使用了libtool,必须在编译和安装libtool包的时候使用与生成autoconfautomake包相同的--prefix--exec-prefix参数。必须在运行上面任何命令前做这个事情。如果没有使用Cygnus,需要运行libtoolize把支持的文件拷贝到工程目录。

如果成功运行上面的命令,就会创建一个空目录,由设置了--enable-maintainer-mode参数的autoconf生成的configure脚本运行,会生成一系列Makefiles文件,包含所有重新构建的规则。

如果后续修改了任何源码,只需要在目录运行make即可,这比自己手动编译要更可靠,因为有很多复杂的相互关联的规则,在使用时很容易忘记。

举例

示例一

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <utime.h>

int
main (argc, argv)
     int argc;
     char **argv;
{
  if (argc != 2)
    {
      fprintf (stderr, "Usage: poke file\n");
      exit (1);
    }

  if (utime (argv[1], NULL) < 0)
    {
      perror ("utime");
      exit (1);
    }

  exit (0);
}
CC = gcc
CFLAGS = -g -O2

all: poke

poke: poke.o
	$(CC) -o poke $(CFLAGS) $(LDFLAGS) poke.o

但是有一些问题,一些老的Unix系统,utime函数不接收第二个NULL参数。其他系统需要传递一个struct utimbuf指针,一些老的系统没有定义这个结构体。

stdlib.h头文件是ANSI C标准,有些老系统不包含。

可以通过autoscan发现这些问题,autoscan会创建configure.scan,这个文件可以修改成configure.in

示例二

使用宏来解决上面的问题

#include <stdio.h>

#ifdef STDC_HEADERS
#include <stdlib.h>
#endif

#include <sys/types.h>

#ifdef HAVE_UTIME_H
#include <utime.h>
#endif

#ifndef HAVE_UTIME_NULL

#include <time.h>

#ifndef HAVE_STRUCT_UTIMBUF

struct utimbuf
{
  long actime;
  long modtime;
};

#endif

static int
utime_now (file)
     char *file;
{
  struct utimbuf now;

  now.actime = now.modtime = time (NULL);
  return utime (file, &now);
}

#define utime(f, p) utime_now (f)

#endif /* HAVE_UTIME_NULL  */

int
main (argc, argv)
     int argc;
     char **argv;
{
  if (argc != 2)
    {
      fprintf (stderr, "Usage: poke file\n");
      exit (1);
    }

  if (utime (argv[1], NULL) < 0)
    {
      perror ("utime");
      exit (1);
    }

  exit (0);
}
# Set this to your installation directory.
bindir = /usr/local/bin

# Uncomment this if you have the standard ANSI/ISO C header files.
# STDC_HDRS = -DSTDC_HEADERS

# Uncomment this if you have utime.h.
# UTIME_H = -DHAVE_UTIME_H

# Uncomment this if utime (FILE, NULL) works on your system.
# UTIME_NULL = -DHAVE_UTIME_NULL

# Uncomment this if struct utimbuf is defined in utime.h.
# UTIMBUF = -DHAVE_STRUCT_UTIMBUF

CC = gcc
CFLAGS = -g -O2

ALL_CFLAGS = $(STDC_HDRS) $(UTIME_H) $(UTIME_NULL) $(UTIMBUF) $(CFLAGS)

all: poke

poke: poke.o
	$(CC) -o poke $(ALL_CFLAGS) $(LDFLAGS) poke.o

.c.o:
	$(CC) -c $(ALL_CFLAGS) poke.c

install: poke
	cp poke $(bindir)/poke

clean:
	rm poke poke.o

开发人员需要知道自己编译的系统对utime的支持情况,然后打开相关的宏。

示例三

编写configure.in脚本来检测系统配置选项,避免手动修改Makefile文件,同样编写Makefile.am来生成Makefile

首先在示例二的poke.c文件中增加#include "config.h"

其次创建一个configure.in文件:

AC_INIT(poke.c)
AM_INIT_AUTOMAKE(poke, 1.0)
AM_CONFIG_HEADER(config.h:config.in)
AC_PROG_CC
AC_HEADER_STDC
AC_CHECK_HEADERS(utime.h)
AC_EGREP_HEADER(utimbuf, utime.h, AC_DEFINE(HAVE_STRUCT_UTIMBUF))
AC_FUNC_UTIME_NULL
AC_OUTPUT(Makefile)

AC_HEADER_STDC

检测标准C语言头文件

AC_CHECK_HEADERS

检测一个头文件是否存在

AC_EGREP_HEADER

检测在某个头文件中的某个字符是否存在,这里就是检测在`utime.h`中的`utimbuf`。

AC_FUNC_UTIME_NULL

检测`utime`是否可以接收NULL参数

Makefile.am文件内容如下:

bin_PROGRAMS = poke

poke_SOURCES = poke.c

这里表示需要编译一个单独的程序,名称为poke。需要安装到bin目录,bin目录有bindir志明。源码是poke.c

还需要增加acconfig.h文件。除了PACKAGEVERSION两个参数外,还需要包含AC_DEFINE提到的HAVE_STRUCT_UTIMBUF

/* Name of package.  */
#undef PACKAGE

/* Version of package.  */
#undef VERSION

/* Whether utime.h defines struct utimbuf.  */
#undef HAVE_STRUCT_UTIMBUF

构建工程

运行如下命令

aclocal
autoconf
autoheader
automake

autoheader会提示所有忘记增加到acconfig.h中的宏。

运行automake会把一些文件添加到我们的目录,可以使用--add-missing自动完成。

默认情况下,automake会在GNU模式下运行,也就是需要我们创建一些额外的文件,比如NEWS, README, AUTHORSChangeLog。也可以使用--foreign参数避免创建这些文件。

运行完这些命令后,会创建这些文件aclocal.m4, configure, config.in, Makefile.in, stamp-h.in

文件

描述一下使用GNU autotool相关的文件

开发文件

由我们编写或者自动生成的文件

关系图

圆角的是命令,方角的是文件

需要编写的开发文件

configure.in(配置脚本)

包含调用`autoconf`的宏,一些标准的shell代码,为解决可移植性问题增加的功能检测模块。最后用`AC_OUTPUT`宏列出需要编译的文件。在使用GNU配置系统是,这个文件是必须的。

Makefile.am(automake输入文件)

描述了代码如何编译。包含`automake`定义的变量,标准`Makefile`规则。

acconfig.h

当配置脚本创建可移植性头文件的时候(`automake`使用`AM_CONFIG_HEADER`宏,非`automake`使用`AC_CONFIG_HEADER`宏),这个文件用于描述那些没有被`autoheader`检测到的宏。这个文件中都是一些`#undef`标识的语句,在`configure.in`中调用`AC_DEFINE`的内容都需要增加到这个文件中。

acinclude.m4(不是必须的)

定义本地的`autoconf`的宏。这些宏可以用在`configure.in`中。实际上你可以不需要本地的`autoconf`宏,而是把所有的内容都写在`configure.in`中,但是使用本地的宏更方便。新版本会忽略`acinclude.m4`文件,取而代之的是一个命名为`m4`的目录,在`Makefile.am`中定义`ACLOCAL_AMFLAGS = -I m4`使`aclocal`从这个目录查找宏定义。`acinclude.m4`只有在使用`automake`的时候才有用,老的工具需要开发人员直接编写`aclocal.m4`文件。

构建开发文件

这些是需要开发人员自己构建的文件。

当使用automake时,这些文件不会在第一次之后手动构建。相反,Makefile会包含自动构建这些文件的规则。如果在configure.in使用AM_MAINTAINER_MODE(Cyguns模式),自动构建的规则只有在配置了--enable-maintainer-mode选项时才会定义。

如果使用自动重构,要确保所有工具都已经安装。

configure 配置脚本

在编译的时候运行。由`autoconf`根据`configure.in`和`aclocal.m4`创建,是一个shell脚本。

Makefile.in

configure脚本把`Makefile.in`转换成`Makefile`。由`automake`根据`Makefile.am`创建。这个文件与标准的`Makefile`文件很像,就是包含了某些变量的配置替代内容。

aclocal.m4

由`aclocal`根据`configure.in`和`acinclude.m4`创建。包含了`autoconf`构建`configure`脚本所需要的宏。也可以在`acinclude.m4`中定义这些宏,或者通过其他工具比如`automake`, `libtool`, `gettext`定义。如果不使用`automake`,就需要自己编写这个文件,这时,如果`configure.in`只用了标准电的`autoconf`的宏,那么这个文件可以不用创建。

config.in

由`autoheader`根据`acconfig.h`和`configure.in`创建的文件。在创建时,`configure`脚本会定义一些宏在这个文件中,这些宏会在工程中被使用。这样就可以使你的C代码根据预处理条件编写不同的功能。这个文件名也有可能是`config.h.in`。

stamp.h-in

由`automake`创建,包含的都是时间戳。用来确定`config.in`是否修改。

编译的文件

关系图

config.statusconfigure创建,是一个脚本,后续又把config.in转化成config.hMakefile.in转化成Makefile

编译文件描述

config.status

编译包的时候需要先运行`configure`脚本,`configure`脚本会创建`config.status`文件,这个是它自己的shell脚本。当运行`configure`的时候会自动运行`config.status`。由`automake`根据`Makefile.in`生成的`Makefile`文件会包含当输入更改时自动运行`config.status`来重新创建某些文件的规则。

Makefile

由`config.status`脚本根据`Makefile.in`创建。

config.h

文件中定义了一些C语言的预处理宏,用来适配不同系统环境的相关功能代码。`config.status`会把`config.in`转换成`config.h`。

config.cache

保存`configure`脚本运行的一些缓存,可以提高速度。如果修改了`configure.in`那么需要删除该文件,运行脚本。

stamp.h

保存的是时间戳,用来判断`config.h`是否修改过。

支持的文件

GNU配置和编译系统的时候需要一些支持文件。正常情况不需要关心。automake使用--add-missing配置和libtoolize都会自动的把这些文件添加到自己的工程中。

可以把这些文件放到一个子目录,用AC_CONFIG_AUX_DIRconfigure.in中定义,automakeconfigure`脚本就可以使用了。

这里介绍一下这些文件,有什么用,为什么需要。

ABOUT-NLS

如果使用`gettext`,由`automake`添加。有关于`gettext`项目的文档。
ansi2knr.c
如果在`Makefile.am`的`AUTOMAKE_OPTIONS`中增加了`ansi2knr`,运行`automake`创建`Makefile`时就会增加。这个文件允许使用K&R C语言编译器编译ANSI C代码。

ansi2knr.1

`ansi2knr.c`的man页面

config.guess

一个脚本语言,决定运行它的配置名称

config.sub

标准化用户输入的配置名称

elisp-comp

用于编译Emacs LISP文件

install-sh

用于安装一个程序的shell脚本。当`configure`脚本无法找到一个程序的时候,会调用这个脚本安装。

ltconfig

用于libtool。是一个shell脚本,为当前使用的特定系统配置libtoot。

ltmain.sh

用于libtool。一个libtool的脚本,通过`ltconfig`配置,用于编译一个类库。

mdate-sh

用于`Makefile`,格式化输出文件修改时间。

missing

用于`Makefile`,当丢失一些条目的时候被用到。

mkinstalldirs

用于`Makefile`安装,创建目录

texinfo.tex

使用`texi2dvi`和`TeX`把Texinfo转换为DVI

ylwrap

用于`Makefile`,来运行一些程序。默认会创建一个固定名字的文件,然后在子目录运行,避免`make`程序并行执行时的冲突。

配置名称

GNU配置系统使用配置名称命名所有的系统名称。这些名称经常是三元组(也有可能是四元组)。

配置名称定义

这是cpu-manufacturer-operating_system形式的字符串,有时候也会是四部分内容:cpu-manufacturer-kernel-operating_system。

在配置选项中使用配置名称时,经常不需要定义全称。架构字段经常缩写,比如i386-linux或者sparc-sunos。脚本文件config.sub会把简短的名字翻译成标准格式。autoconf会在需要的时候调用config.sub

配置名称的字段有这些:

cpu

处理器类型。常见的类型是i386或者sparc。更多的定义也可以使用,比如mipsel——表示小端的MIPS处理器。

manufacturer

一个相对自由定义对的字段,表明系统的架构。一般是unknown。常见的还有pc——IBM一种电脑系统,sun——一种服务器系统。

operating_system

运行软件的操作系统名称。比如solaris2.5或者irix6.3。对于系统版本号没有严格的定义,比如aix4.1.4.0也可以看到。对于嵌入式系统,没有操作系统概念,一般用object文件的类型代替,比如elf或者coff。

kernel

一般用作GNU/Linux。一个标准的GNU/Linux配置名称是i586-pc-linux-gnulibc1。这里内核linux与操作系统gnulibc1名称是分开的。

config.guess运行的时候会打印出当前系统正确的配置名称。脚本使用uname和检测一些其他字段来实现这个功能。

因为config.guess可以确定配置名称,所以一般只会在交叉编译的时候指定配置名称。

使用配置名称

配置脚本有时候会根据配置名称来做不同的选项功能。

最好是根据功能检测而不是系统,因为随着系统的发展,不同系统之间会从其他系统移植一些功能。

检测系统经常在configure.in中完成。对应的语句可能是这样的,假设host保存着标准配置文件的内容,可能使用AC_CANONICAL_HOST或者AC_CANONICAL_SYSTEM宏:

case "${host}" in
i[3456]86-*-linux-gnu*) do something ;;
sparc*-sun-solaris2.[56789]*) do something ;;
sparc*-sun-solaris*) do something ;;
mips*-*-elf*) do something ;;
esac

使用*可以通用匹配config.guess获取的版本。

大部分情况,你需要注意匹配处理器的一个系列。对于很多处理器家族,后面加一个*就足够了,比如上面的mips*。对于i386家族,i[3456]86就足够了。

交叉编译

GNU的配置和编译系统可以用作交叉编译工具。交叉编译工具就是在一个系统上编译可以运行在另一种系统上的工具。

交叉编译概念

一个编译器可以生成在不同系统上运行的程序,这个编译器叫做交叉编译器。类似的概念有交叉汇编,交叉链接。

正常情况,编译器会处理编译和运行在同一个系统上的代码。为了与交叉编译的情况区分,这种编译器称作为本地编译器。同样的有本地汇编等。

虽然调试器并不严格称作为交叉编译工具,但是作为交叉调试器也是有一定意义的:调试器用作调试在另一个系统上运行的代码。下面提到的配置交叉编译工具也同样适用于调试器。

主机和目标

当交叉编译时,有两个不同的系统:一个是编译器运行的系统,一个是编译器为其生成代码的系统。

编译器运行的系统称作为主机系统。

编译器为其生成代码的系统称作为目标系统。

比如,你要在GNU/Linux上生成MIPS嵌入式系统的ELF程序。GNU/Linux就是主机,MIPS ELF就是目标。这个编译器可以叫做GNU/Linux交叉编译MIPS ELF编译器,或者也可以乘坐,i386-linux-gnu交叉编译mips-elf编译器。

正常来说,很多程序并不是交叉编译工具。这些工具没有所谓的目标,比如gcc或者binutils在生成代码的时候并没有所谓的目标。同样还有bison和make。

很多交叉编译工具也可以用作本地编译。对于本地编译工具,提到目标也是有意义的,目标就是主机。比如GNU/Linux本地编译器,主机是GNU/Linux,目标也是GNU/Linux。

使用主机类型

在大部分情况下,主机系统就是你运行configure脚本的系统,也是编译工具的系统(如果这两者之间不一样,可以参考加拿大交叉编译Canadian Cross)。

如果你的configure脚本需要知道主机系统的配置名称——这个包不是交叉编译工具,没有目标——把AC_CANONICAL_HOST宏加入到configure.in中。这个宏会提供几个变量在configure脚本运行时。

host

主机标准的配置名称。通过`config.guess`脚本确定。用户也可以通过`--host`参数覆盖。

host_alias

如果用户使用`--host`参数,这个值就会被覆盖。正常情况下与`host`一样。

host_cpu

host_vendor

host_os

规范配置名称的前三部分。

这些脚本变量可以用作configure.in中。

定义目标

默认情况configure脚本会认为目标和主机是一致的。这是最常见的情况,比如,用本地编译器来代替交叉编译器。

如果你想编译交叉编译工具,必须在运行configure时使用--target明确的指出。--target就是你想要生成代码的系统配置名称。

比如,要构建为MIPS ELF嵌入式系统生成代码的工具,需要使用--target mips-elf

使用目标类型

当编写交叉编译工具的configure.in文件时,你需要使用目标系统的信息。在configure.in增加AC_CANONICAL_SYSTEM宏来实现这个功能。

AC_CANONICAL_SYSTEM将会检查--target,然后使用config.sub获取标准名称。也可以运行AC_CANONICAL_HOST

目标类型会被记录在下面的shell变量中。注意关于这些变量的主机信息也会通过AC_CANONICAL_HOST定义。

target

目标系统标准配置名称

target_alias

`--target`参数指定的内容。如果没有指定,与`host_alias`类似

target_cpu

target_vendor

target_os

标准目标配置名称的前三部分内容

注意,如果hosttarget一样,那么就相当于本地配置;如果不一样,就相当于交叉配置。

hosttarget可以表示同一个系统,但是字符串可能不完全一样。比如,config.guess返回sparc-sun-sunos4.1.4,然后又定义--target sparc-sun-sunos4.1。对于版本号的细微差别,编译工具并不介意。在正常情况下,配置名称差别会比较大,用来判断是否相同。为了方便,一般认为用户定义了--target,但是没有定义--host,就被认为是交叉编辑。

targettarget_alias需要不同处理。

一般情况,用户想要看到的字符串,应该使用target_alias。这包含了所有将要出现在文件系统的信息,比如文件夹名称,或者工具名称。同样也包含任何工具输出,除非明确的标记为标准目标配置名称。允许用户使用--target参数定义显示给外界的内容。

另外,当检测目标系统的特征时,target会被用到。这是因为各种各样的--target参数可能会只想同一个配置名称。你不应该试图复制由config.sub实现的规范化在你的代码中。

为了方便,交叉工具安装会附带由--target指定的前缀。如果不使用--target,就表示本地编译,没有前缀。

比如,如果gcc指定了--target mips-elf,安装文件就会是mips-elf-gcc。如果没有配置--target,就是gcc

autoconf的宏AC_ARG_PROGRAM会帮助你做这些。如果用automake,就不需要做其他的了;程序会自动的使用正确的前缀安装。如果不用automake,那么可以查看autoconf有关AC_ARG_PROGRAM的文档。

在Gygnus树中的交叉编译工具

Cygnus树用于各种包,包括gdb,GNU binutils和egcs。同样也用于Cygnus releases。

在Cygnus树中,configure脚本用作老的Cygnus配置系统,不是autoconf。Makefile.in是用作编译基于在源码树中的包,同样支持编译一大堆在一个configure/make步骤中的工具。

Cygnus树也可以配置--target--target用在每一个子目录,并且允许编译一整套交叉工具。

主机和目标类库

Cygnus树把主机类库和目标类库分开。

主机类库由编译器生成,用于构建主机的程序,也叫做主机编译器。这些类库包含bfdtcl。这些类库由主机编译器构建,然后链接到程序,比如binutils或者gcc。

目标类库由目标编译器构建。如果在源码树中gcc可用,那么目标编译器就是由主机编译器构建的gcc。目标类库有newliblibstdc++。这些类库不会链接到主机程序,但是会用于构建目标编译器程序。

有一个麻烦的地方,配置程序需要知道你使用哪一个编译器构建工具;否则功能测试不能完成。Cygnus树通过在目标编译器构建完成后再配置目标类库来处理这个问题。这样就可以所有的内容都是由同一个configure/make构建,目标类库的配置在make的时候触发。

当目标类库配置后,--target不再使用。相反的是--host--target会用作所有的配置。如果没有--target--host会被传递给config.guess的输出内容。任何--build参数都会被传递下去。

这些配置对的转换已经完成了,因为从目标类库被编译时,它们就已经被构建用于目标的所有配置。根据主机的定义,主机系统和目标系统的整体配置相同。

同样的程序用作本地配置和交叉配置。尽管使用本地配置,目标类库会使用新的编译器编译配置。对于C++类库很重要,因为没有理由假设用于构建主机工具的C++编译器与目标类库的g++编译器使用同样的ABI。

对于本地配置和交叉配置,没有区别。在本地配置中,目标类库经常与主机工具配置编译成同级内容。在交叉配置中,目标库经常在子目录中,目录名称为--target指定的内容。

总结来说,运行configure,配置主机类库和工具,不会配置任何目标类库。运行make会做如下步骤:

  • 编译主机类库
  • 编译主机程序,包括gcc。注意我们会调用gcc用来编译主机程序和目标程序
  • 用新编译的编译器配置目标类库
  • 编译目标类库

步骤不需要完全按照这个顺序执行,因为是由Makefile确定。

目标类库配置脚本

为了为目标库编写配置脚本,您必须了解一些事情。 这只是一个简单的草图,如果初学者没有遵循这里的所有内容,也不用担心。

目标库是使用新构建的目标编译器配置和构建的。 此目标编译器可能没有任何启动文件或库。 事实上,这些文件可能会作为某个目标库的一部分构建,这自然意味着当您配置目标库时它们将不存在。

这意味着目标库的配置脚本可能不使用任何需要进行链接的测试。 不幸的是,这包括许多有用的 autoconf 宏,例如 AC_CHECK_FUNCS。 可以使用进行编译但不进行链接的 autoconf 宏,例如AC_CHECK_HEADERS

这是一个严格的限制,但通常不是致命的限制,因为目标库通常可以假设其他目标库的存在,从而知道哪些功能可用。

在撰写本文时,autoconf 宏“AC_PROG_CC”会创建一个链接以确保编译器正常工作。 这在目标库中可能会失败,因此目标库必须使用一组不同的宏来定位编译器。 有关示例,请参阅目录中的 configure.in 文件,例如 libiberty 或 libgloss。

如前一节所述,目标库有时构建在与主机工具同级的目录中,有时构建在子目录中。 配置库时将传递 --with-target-subdir 配置选项。 如果目标库是兄弟库,它的值将为空字符串。 如果目标库在子目录中,它的值将是子目录的名称。

如果整体构建不是本机构建(即整体配置使用了 --target 选项),则库将配置为 --with-cross-host 选项。 此选项的值将是整个构建的主机系统。 回想一下,库的主机系统将是整个构建的目标。 如果整个构建是本机构建,则不会使用 --with-cross-host 选项。

既可以独立构建也可以作为目标库构建的库可能希望根据情况将自身安装到不同的目录中。 当独立构建或构建本机时,库应安装在“\((libdir)”中。 当构建为非本机目标库时,该库应安装在“\)(tooldir)/lib”中。 --with-cross-host 选项可用于区分这些情况。

--with-cross-host 的相同测试可用于查看是否可以在配置脚本中使用链接测试。 如果未使用 --with-cross-host 选项,则该库是独立构建的或本机构建的,并且链接应该有效。

在Cygnus树中创建目标

Cygnus 树中的顶级“Makefile”定义了每个已知子目录的目标。

对于每个包含宿主库或程序的子目录 dir,“Makefile”目标“all-dir”将构建该库或程序。

宿主工具之间存在依赖关系。 例如,构建 gcc 需要首先构建 gas,因为 gcc 构建过程会调用目标汇编程序。 这些依赖关系反映在顶层的“Makefile”中。

对于每个包含目标库的子目录 dir,“Makefile”目标“configure-target-dir”将配置该库。 Makefile 目标 all-target-dir 将构建那个库。

每个“configure-target-dir”目标都依赖于“all-gcc”,因为目标编译器 gcc 需要配置该工具。 每个“all-target-dir”目标都依赖于相应的“configure-target-dir”目标。

每个目录还有几个其他可能感兴趣的目标:“install-dir”、“clean-dir”和“check-dir”。 目标库也有相应的“目标”版本,例如“install-target-dir”。

目标自由

libiberty 子目录目前是一个特例,因为它是唯一同时使用主机编译器和目标编译器构建的目录。

这是因为在构建主机工具时使用了 libiberty 中的文件,它们也作为支持代码被合并到 libstdc++ 目标库中。

这种二元性不会造成任何特别的困难。 这意味着“所有自由”和“所有目标自由”都有目标。

在本机配置中,当目标库未构建在子目录中时,相同的对象通常用作主机构建和目标构建。 这通常没问题,因为 libiberty 仅包含 C 代码,并且在本机配置中,主机编译器和目标编译器的结果通常是可互操作的。

Irix 6 在这里又是一个例外,因为 SGI 本机编译器默认使用“O32”ABI,而 gcc 默认使用“N32”ABI。 在 Irix 6 上,即使是本机配置,目标库也被构建在一个子目录中,从而避免了这个问题。

目前没有为主机和目标构建其他库,但是添加更多库没有概念上的问题。

Canadian Cross

可以使用 GNU 配置和构建系统来构建一个程序,该程序将在与构建工具的系统不同的系统上运行。 换句话说,可以使用交叉编译器构建程序。

这被称为Canadian Cross。

Canadian Cross例子

这是Canadian Cross的示例。

在 GNU/Linux 上运行时,您可以构建将在 Solaris 系统上运行的程序。 您将使用 GNU/Linux cross Solaris 编译器来构建程序。

当然,您不能在 GNU/Linux 系统上运行生成的程序。 在运行它之前,您必须将它复制到 Solaris 系统。

当然,您也可以先在 Solaris 系统上简单地构建程序。 但是,也许由于某种原因,Solaris 系统不可用; 也许您实际上没有,但您想构建工具供其他人使用。 或者您的 GNU/Linux 系统可能比您的 Solaris 系统快得多。

当构建在非 Unix 系统(例如 DOS 或 Windows)上运行的程序时,最常使用 Canadian Cross 构建。 在 Unix 系统上配置和构建可能比在非 Unix 系统上支持配置机制更简单。

Canadian Cross概念

在构建 Canadian Cross 时,至少涉及两个不同的系统:构建工具的系统和运行工具的系统。

在其上构建工具的系统称为构建系统。

将运行工具的系统称为主机系统。

例如,如果您在 GNU/Linux 系统上构建 Solaris 程序,如前一节所述,构建系统将是 GNU/Linux,而主机系统将是 Solaris。

当然,可以使用 Canadian Cross 构建交叉编译器(即使用交叉编译器构建交叉编译器)。 在这种情况下,生成的交叉编译器为其生成代码的系统称为目标系统。 (有关主机和目标系统的更完整讨论,请参阅主机和目标部分)。

使用 Canadian Cross 构建交叉编译器的示例是在 GNU/Linux 系统上构建 Windows 交叉 MIPS ELF 编译器。 在这种情况下,构建系统将是 GNU/Linux,主机系统将是 Windows,目标系统将是 MIPS ELF。

Canadian Cross 的名称来源于构建、主机和目标系统都不同的情况。 在讨论这些问题时,加拿大拥有三个全国性政党。

构建跨主机工具

为了配置用于Canadian Cross构建的程序,您必须首先构建并安装将用于构建程序的交叉工具集。

这些工具将成为构建跨主机工具。 也就是说,它们将在构建系统上运行,并将生成在主机系统上运行的代码。

这里很容易混淆build和host的意思。 永远记住,构建系统是您进行构建的地方,而主机系统是生成的程序将运行的地方。 因此,您需要一个构建跨主机编译器。

通常,您必须具有完整的交叉环境才能进行构建。 这通常意味着交叉编译器、交叉汇编器等,以及用于主机系统的库和包含文件。

构建和托管选项

当您运行 configure 时,您必须同时使用 --build--host 选项。

--build 选项用于指定构建系统的配置名称。 这通常是运行 config.guess shell 脚本的结果,使用 --build=config.guess 是合理的。

--host 选项用于指定主机系统的配置名称。

正如我们之前解释的那样,config.guess 用于设置 --host 选项的默认值(请参阅使用主机类型部分)。 我们现在可以看到,由于 config.guess 返回运行它的系统类型,它确实识别了构建系统。 由于主机系统通常与构建系统相同(即,人们通常不使用交叉编译器构建),当 - 不使用 -host 选项。

似乎如果在没有使用 --build 选项的情况下使用 --host 选项,configure 脚本可以运行 config.guess 来确定构建系统,并假定 Canadian Cross 如果 config.guess 不同于 --host 选项。 然而,由于历史原因,一些配置脚本通常使用显式的 --host 选项运行,而不是使用 config.guess 中的默认值。 如前所述,很难或不可能可靠地比较配置名称(请参阅使用目标类型部分)。 因此,按照惯例,如果使用了 --host 选项,但未使用 --build 选项,则构建系统默认为主机系统。

Canadian Cross 不在 Cygnus Tree

如果您不使用 Cygnus 树,则必须明确指定要用于构建程序的交叉工具。 这是通过在运行“配置”脚本之前设置环境变量来完成的。

您通常必须至少将环境变量“CC”、“AR”和“RANLIB”设置为要用于构建的交叉工具。

对于某些程序,您还必须设置额外的交叉工具,例如“AS”、“LD”或“NM”。

您可以将这些环境变量设置为您将要使用的构建交叉工具。

例如,如果您在 GNU/Linux 系统上构建 Solaris 程序,并且您的 GNU/Linux cross Solaris 编译器被命名为“solaris-gcc”,那么您可以将环境变量“CC”设置为“solaris-gcc”。

Canadian Cross 在 Cygnus Tree

本节介绍在使用 Cygnus 树时配置和构建Canadian Cross。

建立一个正常的程序

在 Cygnus 树中配置Canadian Cross时,所有适当的环境变量都会自动设置为“host-tool”,其中 host 是用于“--host”选项的值,tool 是工具的名称(例如 、gccas 等)。 这些工具必须在您的“PATH”上。

添加主机前缀将为构建跨主机工具提供通常的名称。 要看到这一点,请考虑在构建这些交叉工具时,它们被配置为在构建系统上运行并为主机系统生成代码。 也就是说,它们配置了一个 --target 选项,该选项与我们现在称为主机的系统相同。 回想一下,已安装的交叉工具的默认名称使用目标系统作为前缀(请参阅使用目标类型部分)。 由于这是我们现在称为主机的系统,因此主机是要使用的正确前缀。

例如,如果您使用 --build=i386-linux-gnu--host=solaris 进行配置,则 Cygnus 树将自动默认使用编译器 solaris-gcc。 您之前必须已经构建并安装了此编译器,可能是通过不使用 --host 选项和使用 solaris--target 选项进行构建。

构建交叉程序

如果您想在 Cygnus 树中使用 Canadian Cross 构建交叉编译器而不是本机编译器,则需要考虑其他因素。

当您使用 Cygnus 树构建交叉编译器时,目标库通常会使用新构建的目标编译器构建(请参阅主机和目标库部分)。 但是,这在使用Canadian Cross构建时不起作用。 这是因为新构建的目标编译器将是一个在主机系统上运行的程序,因此将无法在构建系统上运行。

因此,在使用Cygnus树构建交叉编译器时,必须先安装一套构建交叉目标工具。 构建目标库时将使用这些工具。

请注意,这通常不是Canadian Cross的要求。 例如,可以在构建系统上只构建主机跨目标工具,将工具复制到主机系统,并在主机系统上构建目标库。 Cygnus 树强加了构建跨目标工具的要求,它希望能够在单个“configure”/“make”步骤中构建宿主程序和目标库。 因为它一步构建这些,它希望能够在构建系统上构建目标库,这意味着它必须使用构建跨目标工具链。

例如,假设您要在 GNU/Linux 系统上构建 Windows 交叉 MIPS ELF 编译器。 您之前必须已经安装了 GNU/Linux 跨 Windows 编译器和 GNU/Linux 跨 MIPS ELF 编译器。

为了构建 Windows(配置名称 i386-cygwin32)交叉 MIPS ELF(配置名称 mips-elf)编译器,您可以执行以下命令(长命令行以尾部反斜杠作为延续 特点)。

当您使用 Cygnus 树构建交叉编译器时,目标库通常会使用新构建的目标编译器构建(请参阅主机和目标库部分)。 但是,这在使用Canadian Cross时不起作用。 这是因为新建的目标编译器将是

mkdir linux-x-cygwin32
cd linux-x-cygwin32
srcdir/configure --target i386-cygwin32 --prefix=installdir \
  --exec-prefix=installdir/H-i386-linux
make
make install
cd ..
mkdir linux-x-mips-elf
cd linux-x-mips-elf
srcdir/configure --target mips-elf --prefix=installdir \
  --exec-prefix=installdir/H-i386-linux
make
make install
cd ..
mkdir cygwin32-x-mips-elf
cd cygwin32-x-mips-elf
srcdir/configure --build=i386-linux-gnu --host=i386-cygwin32 \
  --target=mips-elf --prefix=wininstalldir \
  --exec-prefix=wininstalldir/H-i386-cygwin32
make
make install

Cygnus配置

Cygnus 配置脚本早于 autoconf。 它所有有趣的功能都已合并到 autoconf 中。 不应编写新程序来使用 Cygnus 配置脚本。

然而,Cygnus 配置脚本仍在一些地方使用:在 Cygnus 树的顶部和 Cygnus 树中的一些目标库中。 在这些用途被 autoconf 取代之前,这里有一些简短的注释是合适的。 这不是完整的文档,但在检查脚本本身时应该可以将其用作指南。

Cygnus 配置基础

Cygnus 配置不使用任何生成的文件; 没有与“autoconf”对应的程序。 相反,可以在 Cygnus 树的顶部找到一个名为“configure”的 shell 脚本。 这个shell脚本是手写的; 它不是由 autoconf 生成的,在 Cygnus 树的顶层运行 autoconf 是不正确的,而且确实有害。

Cygnus 配置通过检查该目录中的文件“configure.in”在特定目录中工作。 该文件被分成四个独立的 shell 脚本。

第一个是 configure.in 的内容,直到以 # per-host: 开头的一行。 这是公共部分。

第二个是 configure.in 的其余部分,直到以 # per-target: 开头的一行。 这是每个主机部分。

第三个是 configure.in 的其余部分,直到以 # post-target: 开头的一行。 这是每个目标部分。

第四个是 configure.in 的剩余部分。 这是后目标部分。

如果缺少任何这些注释行,则相应的 shell 脚本为空。

Cygnus configure 将首先执行公共部分。 这必须将 shell 变量 srctrigger 设置为源文件的名称,以确认 Cygnus configure 正在寻找正确的目录。 这可能会设置 shell 变量“package_makefile_frag”和“package_makefile_rules_frag”。

Cygnus configure 接下来将设置 buildhost shell 变量,并执行每个主机部分。 这可能会设置 shell 变量“host_makefile_frag”。

Cygnus 配置接下来将设置“目标”变量,并执行每个目标部分。 这可能会设置 shell 变量“target_makefile_frag”。

这些脚本中的任何一个都可以设置 subdirs shell 变量。 这个变量是一个子目录列表,其中可以找到“Makefile.in”文件。 Cygnus configure 将自动在当前目录中查找“Makefile.in”文件。 subdirs shell 变量通常不被使用,我相信目前唯一使用它的目录是 newlib

对于每个“Makefile.in”,Cygnus configure 将通过添加“make”变量(如“host”和“target”)的定义并自动编辑“make”变量(如“prefix”)的值来自动创建一个“Makefile” 如果他们在场。

此外,如果设置了任何 makefile_frag shell 变量,Cygnus configure 会将它们解释为相对于工作目录或源目录的文件名,并将文件的内容读入生成的 Makefile 中。 文件内容将在“Makefile.in”中以“####”开头的第一行之后读入。

这些“Makefile”片段用于为特定主机或目标定制行为。 它们用于选择要编译的特定文件,并通过为随后在编译期间使用的“make”变量提供值来定义特定的预处理器宏。 Cygnus configure 与 autoconf 不同,通常不进行功能测试,并且通常需要为每个

新主机手动添加支持。

Makefile 片段支持类似于 autoconf AC_SUBST_FILE 宏。

创建每个“Makefile”后,将运行 post 目标脚本(即,它可能会运行多次)。 该脚本可以进一步自定义“Makefile”。 当它运行时,shell 变量“Makefile”将保存“Makefile”的名称,包括相应的目录组件。

与 autoconf 生成的“configure”脚本一样,Cygnus configure 将创建一个名为“config.status”的文件,该文件在运行时将自动重新创建配置。 config.status 文件将简单地使用适当的参数再次执行 Cygnus 配置脚本。

configure.in 的任何部分都可以设置 shell 变量 fileslinks。 Cygnus configure 将设置从“links”中的名称到“files”中命名的文件的符号链接。 这类似于 autoconf 的“AC_LINK_FILES”宏。

最后,“configure.in”的任何部分都可以将 shell 变量“configdirs”设置为一组子目录。 如果设置,Cygnus configure 将在每个子目录中递归运行配置过程。 如果子目录使用 Cygnus configure,它将包含一个 configure.in 文件但没有 configure 文件,在这种情况下 Cygnus configure 将递归调用自身。 如果子目录有一个 configure 文件,Cygnus configure 假定它是一个 autoconf 生成的 configure 脚本,并且简单地调用

多库

对于某些目标,gcc 可能有不同的处理器要求,具体取决于命令行选项。 一个明显的例子是在多个处理器上支持的“-msoft-float”选项。 该选项意味着浮点寄存器不可用,这意味着浮点运算必须通过调用仿真子程序而不是使用机器指令来完成。

对于这样的选项,gcc 通常被配置为编译目标库两次:一次使用 -msoft-float,一次不使用。 当 gcc 多次编译目标库时,生成的库称为 multilibs。

Multilibs 并不是真正的 GNU 配置和构建系统的一部分,但我们在这里讨论它们是因为它们需要在用于目标库的“configure”脚本和“Makefile”中得到支持。

gcc 中的多重库

在 gcc 中,multilib 是通过在目标“Makefile”片段中设置变量“MULTILIB_OPTIONS”来定义的。 其他几个“MULTILIB”变量也可以在那里定义。 请参阅使用和移植 GNU CC 中的“目标 Makefile 片段”部分。

如果你已经构建了 gcc,你可以通过使用 -print-multi-lib 选项运行它来查看它使用了什么 multilibs。 输出.; 意味着没有使用 multilibs。 通常,输出是一系列行,每个 multilib 一行。 每行的第一部分,直到“;”,是 multilib 目录的名称。 第二部分是由“@”字符分隔的编译器选项列表。

Multilib 构建在目录树中。 树的顶部,用“.”表示 在 multilib 目录列表中,是未使用特殊编译器选项时使用的默认库。 当使用特定的编译器选项时,树的子目录包含要使用的库版本。

目标库中的 Multilibs

Cygnus 树中的目标库是使用 multilibs 自动构建的。 这意味着每个库都被多次构建。

此默认设置在顶层 configure.in 文件中设置,方法是将 --enable-multilib 添加到为目标库运行时传递给 configure 的参数列表(请参阅主机和目标库部分)。

每个目标库都使用 Doug Evans 编写的 shell 脚本“config-ml.in”来准备构建目标库。 在“configure”脚本创建“Makefile”之后调用此 shell 脚本。 如果没有启用 multilibs,它什么都不做,否则它会修改“Makefile”以支持 multilibs。

config-ml.in 脚本为相应子目录中的每个 multilib 制作一份 Makefile 副本。 在源目录中配置时(不推荐),它将在每个子目录中构建源的符号链接树。

config-ml.in 脚本在各种 Makefiles 中设置了几个变量。 Makefile.in 必须已经有这些变量的定义; config-ml.in 只是改变现有的值。 Makefile 应该为这些变量使用默认值,这将在子目录中做正确的事情。

MULTISRCTOP
config-ml.in 会将其设置为一系列 ../ 字符串,其中字符串的数量是源代码树中 multilib 级别的数量。 默认值应该是空字符串。
多构建顶
config-ml.in 会将其设置为一系列 ../ 字符串,其中字符串的数量是对象目录中多库级别的数量。 默认值应该是空字符串。 这将不同于在源代码树中配置时的“MULTISRCTOP”(不推荐)。
多目录
仅在顶层“Makefile”中,“config-ml.in”会将其设置为 multilib 子目录列表。 默认值应该是空字符串。
多子目录
config-ml.in 会将其设置为安装的子目录名称以用于该子目录,并以/ 开头。 默认值应该是空字符串。
MULTIDO
‘多重清洁’
仅在顶层“Makefile”中,“config-ml.in”会将这些变量设置为执行递归 make 时要使用的命令。 这些变量都应默认为字符串“true”,因此默认情况下不会发生任何事情。

所有对源目录父目录的引用都应该使用变量“MULTISRCTOP”。 不要写“\((srcdir)/..”,你必须写“\)(srcdir)/$(MULTISRCTOP)..”。

类似地,对对象目录父目录的引用应该使用变量“MULTIBUILDTOP”。

在安装目标中,库应该安装在子目录“MULTISUBDIR”中。 安装“\((libdir)\)(MULTISUBDIR)/libfoo.a”,而不是安装“$(libdir)/libfoo.a”。

config-ml.in 脚本还修改了顶层的 Makefile 以添加构建 multilibs 时使用的 multi-domulti-clean 目标。

Makefile 的默认目标应该包括以下命令:

@$(MULTIDO) $(FLAGS_TO_PASS) DO=all multi-do

这假定 $(FLAGS_TO_PASS) 被定义为一组变量以传递给 make 的递归调用。 这将构建所有 multili

经常问的问题

我先运行哪个,autoconfautomake

 除非您第一次向包添加 autoconf 或 automake 支持,否则您不应该手动运行它们。 相反,使用 `--enable-maintainer-mode` 选项进行配置,并让 `make` 来处理它。

autoconf 说了一些关于未定义的宏。

 这意味着你的 `configure.in` 中有宏,它们不是由 `autoconf` 定义的。 您可能正在使用旧版本的 `autoconf`; 尝试构建和安装一个更新的。 确保新安装的 `autoconf` 位于您的 `PATH` 中。 另外,请参阅下一个问题。

我的“配置”脚本中有类似“CY_GNU_GETTEXT”的内容。

 这意味着您的 `configure.in` 中有宏,它们应该在您的 `aclocal.m4` 文件中定义,但实际上没有。 这通常意味着 `aclocal` 不能适当地定义宏。 确保您已经安装了所有需要的软件包。 特别是,确保您已经安装了 libtool(这是定义 `AM_PROG_LIBTOOL` 的地方)和 gettext(这是定义 `CY_GNU_GETTEXT` 的地方,至少在 gettext 的 Cygnus 版本中是这样)。

我的“Makefile”中有“@”字符。

 这可能意味着您试图在您的 `Makefile.in` 中使用 autoconf 替换,而没有将适当的 `AC_SUBST` 调用添加到您的 `configure` 脚本中。 或者它可能只是意味着您需要在构建目录中重建“Makefile”。 要从“Makefile.in”重建“Makefile”,请运行不带参数的 shell 脚本“config.status”。 如果您需要强制再次运行“configure”,请先运行“config.status --recheck”。 这些运行通常由“Makefile”目标自动完成,但是如果你的“Makefile”被搞砸了,你需要帮助他们。

为什么我必须同时运行 config.status --recheckconfig.status

 通常情况下,你不会; 它们将由“Makefile”目标自动运行。 如果您确实需要运行它们,请使用 `config.status --recheck` 使用与第一次运行时相同的参数再次运行 `configure` 脚本。 使用“config.status”(不带参数)根据配置脚本的结果重新生成所有文件(“Makefile”、“config.h”等)。 这两种情况是分开的,因为在运行“config.status --recheck”后并不总是需要重新生成所有文件。 automake 生成的“Makefile”目标将使用环境变量“CONFIG_FILES”和“CONFIG_HEADERS”来仅在需要时重新生成文件。

什么是Cygnus?

 Cygnus 树用于各种包,包括 gdb、GNU binutils 和 egcs。 当然,它也用于 Cygnus 版本。 它是在 Cygnus 开发的构建系统,使用 Cygnus 配置脚本。 它允许使用单个配置和制作构建许多不同的包。 树中的配置脚本正在转换为 autoconf,但一般构建结构保持不变。

为什么我必须不断重建和重新安装工具?

 我知道,这很痛苦。 不幸的是,工具本身存在需要修复的错误,每次发生这种情况时,使用这些工具的每个人都需要重新安装它们的新版本。 在工具稳定之前,我不知道是否会有巧妙的修复方法。

为什么不直接使用 Cygnus 树“make”目标来更新工具呢?

 不幸的是,这些工具需要先安装才能使用。 这意味着它们必须使用适当的前缀来构建,并且假设每个配置都使用适当的前缀似乎是不明智的。 可以让它们就地工作,或者可以将它们安装在某个子目录中; 迄今为止,这些方法尚未得到实施。

https://en.wikipedia.org/wiki/GNU_Autotools
https://airs.com/ian/configure/configure_toc.html

标签:configure,GNU,--,Makefile,Automake,编译器,构建,Autoconf,config
From: https://www.cnblogs.com/studywithallofyou/p/17097780.html

相关文章