注:本文中的“构建”特指 build,“编译”指 compile
安装 GMP
本段原文链接: gmplib.org/manual/Inst…
GMP 项目使用基于 autoconf/automake/libtool 的配置系统进行配置。在 Unix 类系统中,可以用下面的命令完成基本的构建:
./configure
make
可以用下面的命令进行功能测试:
make check
可以用下面的命令来安装 GMP (默认安装至/usr/local):
make install
构建选项
本段原文链接: gmplib.org/manual/Buil…
所有常用的 autoconf 配置选项都是可用的,可以使用 ./configure --help 来查看这些选项。此外, INSTALL.autoconf 文件也包含了一些通用的安装信息。
工具
configure 需要多种 Unix 类系统提供的工具。对于非 Unix 类系统,请参阅特殊系统注意事项。
如果不想用 configure 进行构建也许也是可行的,毕竟目录中包含所有的源代码。但那样你需要自己解决很多问题。
构建目录
如果想要在其他目录(而非源码目录)构建,要首先 cd 到那个目录中,然后使用绝对路径来指定调用 GMP 源码目录下的 configure ,例如:
cd /my/build/dir
/my/sources/gmp-6.2.1/configure
并非所有的 make 工具都包含了切换目录所需的特性(VPATH),例如 SunOS 和 Slowaris make 的 bug 会导致这些工具无法切换目录构建。请考虑换用 GNU make 。
--prefix 和 --exec-prefix 选项
--prefix 选项可以为 GMP 指定安装目录。该选项的默认值为 /usr/local 。
--exec-prefix 选项指定架构相关文件(例如 libgmp.a )的安装位置。该选项可实现在隔离架构相关文件的前提下,共享架构无关的部分文件(如文档)。需要注意, gmp.h 定义了 libgmp 中一部分的编码,这导致该文件也是架构相关的,因此需要保证该文件在 $prefix/include 和 $exec_prefix/include 中都可被编译器搜索到
--disable-shared, --disable-static 选项
GMP 默认会编译静态和动态两种库,但我们可以手动禁用其中的某一种。共享库能帮助生成更小的可执行文件,可以让多个进程共享一份代码,但在某些 CPU 上可能会稍微减慢运行速度,并会在每次函数调用时都产生一点额外开销。
本地编译( Native Compilation ),--build=CPU-VENDOR-OS
对于普通的本地编译,可以使用 --build 选项来指定系统。默认情况下,./configure 会使用 ./config.guess 的输出(译注:config.guess 是一个 gmp 源码包中的工具,直接运行会得到一个代表着系统类型的文本输出。例如我的是 nehalem-pc-linux-gnu)。在某些系统中, config.guess 可以确定具体的 CPU 类型,但如果不能给出,就需要在配置时显式指定了。例如:
./configure --build=ultrasparc-sun-solaris2.7
在各种情况下, "OS" 部分都是必要的,因为这会影响 libtools 如何生成共享库。如果不知道该填什么,可以通过运行 ./config.guess 来获取该值。
交叉编译,--host=CPU-VENDOR-OS
在交叉编译时,使用 --build 指定编译机的系统,使用 --host 指定 GMP 库将要运行的目标系统。例如,使用 FreeBSD Athlon 系统编译 m68k 的 GNU/Linux 二进制文件,命令如下:
./configure --build=athlon-pc-freebsd35 --host=m68k-mac-linux-gnu
首先会使用 host 系统类型作为前缀(prefix)来寻找编译工具。例如这里会先尝试使用 m68k-mac-linux-gnu-ranlib ,然后再尝试用 ranlib。这能让交叉编译工具和本地(native)工具共存。--host 所指定的值会被用于所用编译工具的前缀,该值也可以是别名,例如 m68k-linux。但需要注意,并不是只有这一种方式能够设置所用的工具,也可以只设置一个包含了交叉编译工具(例如 cc 等)的 PATH 环境变量来设置所用工具。
为同一个 CPU 家族的不同 CPU 编译程序也是一种交叉编译。尽管这可能只需要在本地编译器中加一个特殊选项。在任何情况下,./configure 都会避免构建依赖于用于构建的系统的代码,这对于为较新的 CPU 创建二进制文件时很重要,因为这样的二进制程序可能不会需要在构建系统上运行。
在所有的情况下,编译器都能将一个标准的 C main 程序构建为二进制可执行文件(无论是什么格式)。即使组成 libgmp 的只有对象文件,./configure 还会出于某些目的进行链接测试,例如确定 host 系统上有哪些函数可用。
当前在进行交叉编译时,除非显式指定 --build 选项,否则 configure 都会给出一个警告:因为在 PATH 中只有一个交叉编译 cc 的情况下,只靠 PATH 可能无法准确推断用于构建的系统的类型。
注意,--target 选项不适用于 GMP 。该选项通常是构建编译工具时使用的:构建编译工具时,使用 --host 指定工具运行在哪里,使用 --target 指定工具生成的代码要运行在哪里。普通程序以及 GMP 这样的库,只需要 --host 选项指定将运行的环境即可。(过去某些版本的 GMP 中,曾误用过 --target 选项)。
CPU 类型
通常而言,如果想要让程序运行速度尽可能快,就应该为 GMP 配置具体的 CPU 类型。然而这可能会导致二进制文件无法运行在同一个 CPU 家族的早期版本上,在同一 CPU 家族中更旧或更新的 CPU 上也可能运行得更慢。最好的做法是,总为要运行 GMP 的设备类型构建专属的 GMP 。
下面是目前 GMP 支持的 CPU 。若想知道具体选用的代码和编译器选项,请查看 configure.ac
- Alpha: ‘alpha’, ‘alphaev5’, ‘alphaev56’, ‘alphapca56’, ‘alphapca57’, ‘alphaev6’, ‘alphaev67’, ‘alphaev68’ ‘alphaev7’
- Cray: ‘c90’, ‘j90’, ‘t90’, ‘sv1’
- HPPA: ‘hppa1.0’, ‘hppa1.1’, ‘hppa2.0’, ‘hppa2.0n’, ‘hppa2.0w’, ‘hppa64’
- IA-64: ‘ia64’, ‘itanium’, ‘itanium2’
- MIPS: ‘mips’, ‘mips3’, ‘mips64’
- Motorola: ‘m68k’, ‘m68000’, ‘m68010’, ‘m68020’, ‘m68030’, ‘m68040’, ‘m68060’, ‘m68302’, ‘m68360’, ‘m88k’, ‘m88110’
- POWER: ‘power’, ‘power1’, ‘power2’, ‘power2sc’
- PowerPC: ‘powerpc’, ‘powerpc64’, ‘powerpc401’, ‘powerpc403’, ‘powerpc405’, ‘powerpc505’, ‘powerpc601’, ‘powerpc602’, ‘powerpc603’, ‘powerpc603e’, ‘powerpc604’, ‘powerpc604e’, ‘powerpc620’, ‘powerpc630’, ‘powerpc740’, ‘powerpc7400’, ‘powerpc7450’, ‘powerpc750’, ‘powerpc801’, ‘powerpc821’, ‘powerpc823’, ‘powerpc860’, ‘powerpc970’
- SPARC: ‘sparc’, ‘sparcv8’, ‘microsparc’, ‘supersparc’, ‘sparcv9’, ‘ultrasparc’, ‘ultrasparc2’, ‘ultrasparc2i’, ‘ultrasparc3’, ‘sparc64’
- x86 family: ‘i386’, ‘i486’, ‘i586’, ‘pentium’, ‘pentiummmx’, ‘pentiumpro’, ‘pentium2’, ‘pentium3’, ‘pentium4’, ‘k6’, ‘k62’, ‘k63’, ‘athlon’, ‘amd64’, ‘viac3’, ‘viac32’
- Other: ‘arm’, ‘sh’, ‘sh2’, ‘vax’,
没有列出的 CPU 都使用通用的 C 代码。
通用 C 构建
如果某些汇编代码会产生问题,或者有某些其他的需求,可以通过配置 --disable-assembly 来指定使用通用的 C 代码。
需要注意这可能会减慢运行速度,但应该会有更好的可移植性,让之前汇编代码无法运行的功能运行起来。
胖二进制(Fat binary), --enable-fat
使用 --enable-fat 可以在 x86 上编译“胖二进制”代码,这能让程序在运行时根据具体的 CPU 类型来选择优化的低层子程序( low level subroutines )。这会增大二进制文件的体积,换来在所有的 x86 芯片上都获得很好的性能表现。(该选项未来可能会支持更多的架构类型)
ABI
在某些系统中,GMP 支持多个 ABI (应用二进制接口,Application Binary Interfaces),即数据类型的大小和约定。GMP 会默认选择最佳的 ABI ,但你也可以手动指定,例如:
./configure --host=mips64-sgi-irix6 ABI=n32
请参阅ABI 和 ISA 了解更多可选值,及应用需要注意的相关事项
CC, CFLAGS
默认情况下,构建 GMP 所选用的 C 编译器是在几个候选项中选出来的,若有 gcc 可选,则优先使用 gcc 。可以通过 CC=whatever 来将某个具体要使用的编译器传给 ./configure 。
对于各种不同的系统,默认的编译器标志( flags )都是基于 CPU 和编译器设置的。可以通过 CFLAGS="-whatever" 来将值传给 ./configure 以设置特定的标志。
被使用的 CC、CFLAGS 会在 ./configure 的过程中打印出来,也可以在生成的 Makefile 中找到。这是检查默认值并考虑修改这两个值的最简单方式。
注意,当为一个支持多 ABI 的系统手动指定 CC 和 CFLAGS 时,需要显式指定 ABI=whatever 。因为 GMP 无法只通过标志来确定 ABI ,也就无法选择正确的汇编代码。
如果仅指定了 CC ,则会使用该编译器默认的 CFLAGS (如果 GMP 能够识别编译器的话)。例如指定 CC=gcc 就可以强制使用 GCC ,并使用默认的标志(以及默认 ABI )。
CPPFLAGS
任何类似于 -D 的定义标志或类似于 -I 的预处理器所需 include 标志,都需要在 CPPFLAGS 中进行设置,而非 CFLAGS 中。编译过程会使用到 CPPFLAGS 和 CFLAGS 两个标志,但预处理中指挥使用 CPPFLAGS 标志。存在这个区别是因为,绝大多数预处理器都不会接收编译器会接收的标志。预处理在某些配置测试中是分开进行的。
CC_FOR_BUILD
某些构建时程序( build-time programs )会被编译并运行,以生成 host 相关的数据表( host-spcific data tables )。CC_FOR_BUILD 就是用于该用途的编译器。其不需要被设置为任何特定的 ABI 或模式,只要能生成可运行的可执行文件即可。该选项的默认值是使用 CC 给定的编译器,或例如 cc、gcc 这样的工具。
这种编译器不需要额外的标志,因为通常只需要进行最简单的、类似于 cc foo.c 这样的使用就足够了。如果一定要加上某些特殊的选项,直接在 cc 名称后面加上即可,例如 CC_FOR_BUILD="cc -whatever"。
C++ 支持,--enable-cxx
GMP 可以通过 --enable-cxx 来启用 C++ 支持,这种情况下会用到 C++ 编译器。只有在能找到编译器的情况下,才能用 --enable-cxx=detect 来启用 C++ 支持。C++ 支持由 libgmpxx.la 库和 gmpxx.h 头文件组成(参阅 头文件和库)
为 C++ 支持提供一个专用的 libgmpxx.la 而不是将 C++ 对象加入到 libgmp.la ,是为了确保动态链接的 C 程序不会因为依赖 C++ 标准库的代码而变臃肿,并避免出现在链接纯 C 程序时用到 C++ 编译器的情况。
libgmpxx.la 会使用一些 libgmp.la 中的内部逻辑,并只能和相同 GMP 版本的 libgmp.la 协同使用。未来对这些内部逻辑的修改也可能会包含重命名,因此造成的匹配错误可能会带来符号解析失败的问题,而不会有其他诡异的错误行为。
通常来说,libgmpxx.la 只能由构建它所用的 C++ 编译器使用,因为不同编译器的名称修改和运行时支持通常是不兼容的。
CXX, CXXFLAGS
当启用 C++ 支持时,可以通过CXX, CXXFLAGS来设置 C++ 编译器以及相应的标志。默认的 CXX 是一个候选编译器列表中的第一个,当 g++ 可用时会优先使用 g++ 。CXXFLAGS 会默认尝试使用 CFLAGS、去掉 -g 的 CFLAGS ,对于 g++ 会使用 -g -O2 或 -O2,对于其他编译器会使用 -g 或不使用任何标志。当同时使用 gcc 和 g++ 时,可以尝试只使用 CFLAGS,因为 gcc 可用的标志通常也可以直接用于 g++。
保持 C 和 C++ 编译器相匹配是很重要的,因这意味着它们的启动和运行时支持程序相兼容,它们生成的代码也有相同的 ABI (如果系统支持多个 ABI 的话)。./configure 目前还无法很好地检查这些东西,因此GMP默认启用 disable-cxx 选项,以避免由编译器不匹配造成的构建失败问题。该情况或许能在未来有所改变。
此外,不建议直接将 CXX 设置为 CC 。虽然 gcc 能将 foo.cc 识别为 C++ 代码,但只有 g++ 能够在用 C++ 对象文件编译可执行文件和动态库时,以正确的方式启动链接器。
临时内存,--enable-alloca=<choice>
GMP 使用下面三个方法来分配临时工作区。例如,可以使用 --enable-alloca=malloc-reentrant 来选择具体要用的方法为 malloc-reentrant。
alloca- C 库或编译器内建;malloc-reentrant- 堆, 通过可重入方式;malloc-notreentrant- 堆,使用全局变量。
为了方便,还可以使用下面这些选项。--disable-alloca 等同于 no
yes- 等同于alloca;no- 等同于malloc-reentrant;reentrant- 如果可用,值为alloca,否则是malloc-reentrant。该项是默认值;notreentrant- 如果可用,值为alloca,否则是malloc-notreentrant
alloca 可重入而且速度快,是推荐选项。该选项会在栈上分配较小的块。对于大的块还是会使用 malloc-reentrant;
malloc-reentrant 是可重入且线程安全的。但 malloc-notreentrant 的速度更快,在不需要可重入特性的时候应优先选用;
两个内存分配方法实际上使用由 mp_set_memory_functions 所选择的内存分配函数,默认是 malloc 等函数。详情请参阅 自定义分配 。
还有一个 --enable-alloca=debug 选项可用,其能帮助调试内存相关问题(详情参阅 调试)
FFT 乘法, --disable-fft
默认乘法是用 Karatsuba, 3-way Toom, high degree Toom 以及 Fermat FFT。FFT 仅用于大和超大操作数,如有需要可以禁用以减小代码体积。
断言检查( Assertion Checking ),--enable-assert
该选项可启用一些库中的一致性检查。该选项用于调试,详情参阅 调试
执行分析( Execution Profiling ),--enable-profiling=prof/gprof/instrument
启用不同种类的分析支持,详情参阅 分析
MPN_PATH
每个 MPN 子程序提供了不同版本的汇编代码。对于特定的 CPU ,会在预定的 PATH 中搜索每个 MPN 的最佳版本代码。例如 sparcv8 有
MPN_PATH="sparc32/v8 sparc32 generic"
这意味着会最先找 v8 代码,然后是 sparc32(即 v7),最后返回到通用 C 。有相关知识和特殊需求的用户可以指定一个不同的 path。通常完全没必要修改该值。