1. 引言
gmp 是一个用于任意精度整数、有理数和浮点数运算的高效C语言库;mpfr 构建在 gmp 之上,专注于正确舍入的任意精度浮点运算。这两个库都是非常底层的库,通常一起使用。
2. 构建
使用本系列文章(《CMake构建学习笔记-目录》)实现的自动化工具 BuildCppDependency 来进行构建 gmp 和 mpfr。以 gmp 为例,在 Windows 平台下输入指令:
powershell
./BuildCppDependency.ps1 `
-Generator "Visual Studio 16 2019" `
-InstallDir "$env:GISBasic" `
-SymbolDir "$env:GISBasic/symbols" `
-Install gmp
在 Linux (Ubuntu) 平台下输入指令:
bash
./build.sh -install gmp -installdir "$GISBasic"
虽然可以直接使用工具,但是还是说一下构建的细节。在 Windows 平台下,想用 MSVC 来构建 gmp 和 mpfr 还是挺困难的,因为 gmp 和 mpfr 是 GNU 项目,只提供 Linux 下的构建方式。要组织成 CMake 项目需要对项目本身有一定的了解,所以笔者这里也不硬搞了,直接使用了 vcpkg 的预编译包,指令的实现其实就是将这个预编译包解压安装。
不过在 Linux/Ubuntu 下就可以自己编写脚本,使用 Autotools + GCC + Make 工具链来进行构建了。gmp的构建脚本如下:
bash
#!/bin/bash
# ===========================================
# gmp.sh - 构建 GMP 库
# 接收参数:
# -installdir <dir> # 安装目录(必须)
# -force # 强制重新构建
# -noclean # 不清理临时文件
# ===========================================
set -e # 遇到错误立即退出
# 默认值
InstallDir=""
FORCE=false
NOClean=false
# 解析可选参数
while [[ $# -gt 0 ]]; do
case $1 in
-installdir)
InstallDir="$2"
shift 2
;;
-force)
FORCE=true
shift
;;
-noclean)
NOClean=true
shift
;;
--) # 分隔符,后面是项目参数
shift
break
;;
-*)
echo "未知参数: $1"
exit 1
;;
*)
break # 非选项参数开始,停止解析
;;
esac
done
# 检查必要参数
if [[ -z "$InstallDir" ]]; then
echo "❌ 错误: 必须指定 -installdir <安装目录>"
exit 1
fi
# 项目配置
InstallDir=$(realpath "$InstallDir")
ScriptDir=$(pwd)
SourceBaseDir=$(realpath "../Source") # 绝对路径
Name="gmp-6.3.0"
SourceZipFile="${SourceBaseDir}/${Name}.tar.xz"
ExtractedSourceDir="${SourceBaseDir}/${Name}"
BuildDir="${ScriptDir}/build-${Name}" # 明确区分 build 目录
TargetFile="${InstallDir}/include/gmp.h"
# 检查源码包是否存在
if [[ ! -f "$SourceZipFile" ]]; then
echo "❌ 源码包未找到: $SourceZipFile"
exit 1
fi
# 如果没有 -force 且目标文件已存在,跳过构建
if [[ "$FORCE" == false && -f "$TargetFile" ]]; then
echo "✅ GMP 已安装: $TargetFile,跳过构建(使用 -force 可强制重建)"
exit 0
fi
if [[ "$FORCE" == true ]]; then
echo "⚠️ 启用 -force 模式,将重新构建 GMP"
# 清理旧的构建目录(如果存在)
rm -rf "$BuildDir"
fi
echo "🔍 开始构建 GMP: $Name"
echo "📦 源码包: $SourceZipFile"
echo "📂 解压目录: $ExtractedSourceDir"
echo "⚙️ 构建目录: $BuildDir"
echo "📁 安装目录: $InstallDir"
# === 1. 解压源码(如果尚未解压)===
if [[ ! -d "$ExtractedSourceDir" ]]; then
echo "📦 正在解压源码..."
tar -xf "$SourceZipFile" -C "../Source/"
else
echo "📂 源码已存在,跳过解压"
fi
# === 2. 创建并进入构建目录(推荐 out-of-source build)===
mkdir -p "$BuildDir"
cd "$BuildDir"
# === 3. 配置 ===
echo "🔧 正在运行 configure..."
"$ExtractedSourceDir/configure" \
--prefix="$InstallDir" \
--enable-cxx \
--enable-fat # CPU优化
# === 4. 编译 ===
echo "🔨 正在编译 GMP..."
make -j$(nproc)
# === 5. 安装 ===
echo "📥 正在安装 GMP 到 $InstallDir..."
make install
# === 6. 清理临时文件 ===
if [[ "$NOClean" == false ]]; then
echo "🧹 正在清理临时目录..."
rm -rf "$ExtractedSourceDir" && echo "🗑️ 已删除源码目录: $ExtractedSourceDir"
rm -rf "$BuildDir" && echo "🗑️ 已删除构建目录: $BuildDir"
else
echo "🚫 已启用 -noclean,保留构建目录: $BuildDir"
fi
echo "🎉 项目 $Name 构建完成"
cd -
其实就是很标准的 Autotools 工具链的构建流程,先 configure,再 make,最后 make install 。其中的一个关键也是看 configure 过程中的构建选项,例如这里的--enable-fat,表示开启CPU优化。
构建 mpfr 的脚本则是:
bash
#!/bin/bash
# ===========================================
# mpfr.sh - 构建 MPFR 库
# 接收参数:
# -installdir <dir> # 安装目录(必须)
# -force # 强制重新构建
# -noclean # 不清理临时文件
# ===========================================
set -e # 遇到错误立即退出
# 默认值
InstallDir=""
FORCE=false
NOClean=false
# 解析可选参数
while [[ $# -gt 0 ]]; do
case $1 in
-installdir)
InstallDir="$2"
shift 2
;;
-force)
FORCE=true
shift
;;
-noclean)
NOClean=true
shift
;;
--) # 分隔符,后面是项目参数
shift
break
;;
-*)
echo "未知参数: $1"
exit 1
;;
*)
break # 非选项参数开始,停止解析
;;
esac
done
# 检查必要参数
if [[ -z "$InstallDir" ]]; then
echo "❌ 错误: 必须指定 -installdir <安装目录>"
exit 1
fi
# 项目配置
InstallDir=$(realpath "$InstallDir")
ScriptDir=$(pwd)
SourceBaseDir=$(realpath "../Source") # 绝对路径
Name="mpfr-4.2.2"
SourceZipFile="${SourceBaseDir}/${Name}.tar.xz"
ExtractedSourceDir="${SourceBaseDir}/${Name}"
BuildDir="${ScriptDir}/build-${Name}" # 明确区分 build 目录
TargetFile="${InstallDir}/include/mpfr.h"
# 检查源码包是否存在
if [[ ! -f "$SourceZipFile" ]]; then
echo "❌ 源码包未找到: $SourceZipFile"
exit 1
fi
# 如果没有 -force 且目标文件已存在,跳过构建
if [[ "$FORCE" == false && -f "$TargetFile" ]]; then
echo "✅ MPFR 已安装: $TargetFile,跳过构建(使用 -force 可强制重建)"
exit 0
fi
if [[ "$FORCE" == true ]]; then
echo "⚠️ 启用 -force 模式,将重新构建 MPFR"
# 清理旧的构建目录(如果存在)
rm -rf "$BuildDir"
fi
echo "🔍 开始构建 MPFR: $Name"
echo "📦 源码包: $SourceZipFile"
echo "📂 解压目录: $ExtractedSourceDir"
echo "⚙️ 构建目录: $BuildDir"
echo "📁 安装目录: $InstallDir"
# === 1. 解压源码(如果尚未解压)===
if [[ ! -d "$ExtractedSourceDir" ]]; then
echo "📦 正在解压源码..."
tar -xf "$SourceZipFile" -C "../Source/"
else
echo "📂 源码已存在,跳过解压"
fi
# === 2. 创建并进入构建目录(推荐 out-of-source build)===
mkdir -p "$BuildDir"
cd "$BuildDir" > /dev/null
# === 3. 配置 ===
# 注意:MPFR 依赖 GMP,需确保能正确找到 GMP(头文件 + 库)
echo "🔧 正在运行 configure..."
"$ExtractedSourceDir/configure" \
--prefix="$InstallDir" \
--with-gmp="$InstallDir" \
--enable-thread-safe
# === 4. 编译 ===
echo "🔨 正在编译 MPFR..."
make -j$(nproc)
# === 5. 安装 ===
echo "📥 正在安装 MPFR 到 $InstallDir..."
make install
# === 6. 清理临时文件 ===
if [[ "$NOClean" == false ]]; then
echo "🧹 正在清理临时目录..."
rm -rf "$ExtractedSourceDir" && echo "🗑️ 已删除源码目录: $ExtractedSourceDir"
rm -rf "$BuildDir" && echo "🗑️ 已删除构建目录: $BuildDir"
else
echo "🚫 已启用 -noclean,保留构建目录: $BuildDir"
fi
echo "🎉 项目 $Name 构建完成"
cd - > /dev/null
可以看到,脚本内容基本都差不多。两者其实可以抽象出一个通用的构建脚本,用来针对于 Autotools 工具链构建的情况。不过这个工作就放到后续来做了。
3. 其他
系列文章:《CMake构建学习笔记-目录》 构建工具: Github地址,GitCode地址 二进制构建结果:Github地址,GitCode地址