将静态库添加到 C 或 C++ 项目的常用方法是啥?

Posted

技术标签:

【中文标题】将静态库添加到 C 或 C++ 项目的常用方法是啥?【英文标题】:What is the usual way to add static libraries to a C or C++ project?将静态库添加到 C 或 C++ 项目的常用方法是什么? 【发布时间】:2016-03-06 18:12:20 【问题描述】:

基本问题 - 我正在学习 C 和 C++ 编程。我不确定如何处理这些语言的依赖管理。

我想在我的项目中添加一个静态库。说明项目需要该库并将该库包含在项目中的通常方式是什么?

我有兴趣了解如何在基于 makefile 的项目中执行此操作(而不是使用 CMake)。对于我所看到的,CMake 允许您使用 ExternalProject_Add 函数自动化依赖管理,但我对不使用 CMake 的常用方法很感兴趣。

感谢您的帮助!

【问题讨论】:

您可能对this QandA感兴趣。 需要考虑的一点是:能够对静态库中的代码进行更改(例如修复错误或修改其中的功能)对您来说有多重要?如果您想保留该功能,最好将库的源代码签入您的存储库,并将其作为程序构建过程的一部分进行构建。 Makefile 不做包管理;无法在其中指定“您必须有包/库 x”。通常,您要么配置 automake 以检查库的存在,要么在自述文件中添加注释,说明库 x 是必需的。我不会在您的 source 控件中包含已编译的二进制文件。 感谢@ColonelThirtyTwo。我的印象是 make 与包管理没有任何关系,但由于 CMake 似乎能够在某种程度上帮助解决这个问题,我想知道是否也有一些方法可以在 make 中做到这一点。我通常不会将二进制库添加到源代码控制中,但由于我不熟悉 C 世界,我不想假设那不是方式。顺便听说过biicode,可惜好像没有被广泛采用。 谢谢@JeremyFriesner。不,我不认为我需要那个。我的问题更多是关于 C 程序员通常如何处理这些情况,我的意思是通常的常见方法是什么。还是谢谢。 【参考方案1】:

我假设您想按原样使用第三方库,而无需您进行任何自定义修改。我的回答也将针对 GNU/Linux,但由于您正在编写自己的 Makefiles,我认为这是适合您的相关平台。

虽然将库转储到您的存储库中似乎是一种方便的快速修复,但这并不是一个好的做法。理想情况下,您的存储库应该只包含您的项目负责的手写文件。这保持了关注点的清晰分离。

如果您的项目需要 libfoo,我感兴趣的另一个项目可能也需要它,因此我可能决定在我的系统上安装 libfoo 并将其用于所有需要它的项目。我可以通过手动下载、构建和安装 libfoo 来做到这一点,或者,如果我幸运的话,我可以通过我的包管理器安装它。手动构建和安装时,至少有两个选项。我只能为我的用户在系统范围内或本地安装它。另一方面,如果我认为我不再需要 libfoo 或者您的项目需要特定版本的 libfoo 而不是我通常想要使用的版本,我可能更愿意在本地目录中构建 libfoo 而不是安装完全没有。

总而言之,您的用户的选项是。

    使用系统的包管理器在系统范围内安装库(例如在/usr/lib/ 中)。 在系统范围内手动下载、构建和安装库(例如/usr/local/lib/)。 仅为我的本地用户手动下载、构建和安装库(例如~/lib/)。 手动下载并构建库但不要安装它(例如~/src/foo-1.42/)。

应该由您的用户决定选择哪个选项。但是,虽然您不应该对他们强加任何东西,但您应该尽一切可能帮助他们。

处理外部依赖项的第一件事是记录它们。在您的README 文件中,列出项目的所有依赖项以及相应项目下载页面的 URL。如果您知道相关操作系统已经打包了该库,还请提及人们必须为该系统安装的软件包的名称。我知道的所有 GNU/Linux 发行版都有一个网站,您可以在其中搜索它们的包索引,因此您可能想要为更流行的那些进行搜索。如果您的项目需要特定版本的库,请不要忘记在显着位置提及这一点。

如果您的用户决定使用选项 (1),则无需再做任何事情。他们将使用包管理器安装库,您的Makefile 将从LIBS 变量中引用它(例如-lfoo)。

如果您的用户决定(或必须,因为该库未针对他们的系统打包)选择选项 (2) 或 (3),情况并没有太大不同。他们将下载、构建和安装库,一旦完成,您的Makefile 将再次获取它。但是,如果他们将库安装在非标准位置,链接器可能无法直接找到它。因此,您的Makefile 使用LDFLAGS 变量非常重要,以便用户可以向其中添加相应的选项(例如-L$HOME/lib/)。如果您的代码正在引用包中的标头,则包含路径(例如-I$HOME/include/)也是如此。这些选项属于CPPFLAGS 变量。

如果您的用户使用选项 (4),他们肯定必须使用链接器标志才能找到库。例如,如果将 libfoo 下载并构建到子目录 foo 中,他们会将 -L./foo/ 添加到 LDFLAGS。但是,在这种情况下,您可以让用户的生活更轻松一些。在项目的***目录中放置一个小 shell 脚本,用于下载并选择性地配置和构建所有外部依赖项。请清楚地记录哪些操作将从 Internet 下载内容,并确保用户知道他们想要下载的内容。此外,请让您的脚本在对下载的包进行任何操作之前验证它们的校验和。不这样做是攻击者的潜在切入点,您不希望您的用户通过使用您的软件而被利用。在这种情况下,您的Makefile(或者更好的是,您的configure 脚本)应该检测到包是在本地构建的并使用它(即添加各自的-I…-L… 标志)。您也可以无条件添加标志,因为预处理器和链接器会默默地忽略不存在的目录。

编写帮助脚本并不难。一个简单的版本可能如下所示。

#! /bin/bash -eu

packages=(foo bar)
declare -A urls
urls['foo']='https://download.foo.org/foo-1.42.tar.gz'
urls['bar']='https://download.bar.org/bar-2.50.tar.gz'

cat <<'EOF' > dependency-checksums.sha1
0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33  foo-1.42.tar.gz
62cdb7020ff920e5aa642c3d4066950dd1f01f4d  bar-2.50.tar.gz
EOF

for pkg in "$packages[@]"
do
    wget "$urls[$pkg]" || exit
done

sha1sum --check dependency-checksums.sha1 || 
    echo "ALERT: Verification of package integrity failed.  Stop." >&2
    exit 1


for pkg in "$packages[@]"
do
    ar="$urls[$pkg]##*/"
    dir="$ar%.tar*"
    tar -xf "$ar"
    ln -s "$dir/" "$pkg"
    ( cd "$dir" && ./configure && make )
done

你可以考虑稍微打磨一下。例如,让它理解--help 选项,只提供下载而不是构建包。当然,您不必编写 shell 脚本。您可以提供 Perl 或 Python 脚本,甚至是 Make 脚本。事实上,像我在上面的示例中那样使用花哨的 Bash 功能并不是一个好主意,因为很多人不使用现代 Bash shell。

如果您将软件作为源存档发布,那么提供已包含所有外部依赖项的替代 tarball 并没有错,这样您的用户就不必单独下载它们。但是你应该只提供这个作为替代方案,而不是唯一的选择。对于 tarball,repository - 如前所述 - 应尽可能远离第三方内容。

虽然编写一个体面的“下载我的依赖项”脚本很容易,但编写灵活的configure 脚本和Makefiles 是乏味的,而且你可能会弄错。您应该认真考虑为此使用自动化框架。 GNU 软件包通常使用 GNU Autotools,即Autoconf 和Automake。如果你想了解更多关于这些工具的信息,我可以推荐 John Calcote 的 book“Autotools – A Practioner's Guide to GNU Autoconf, Automake, 和 Libtool”。

【讨论】:

这是一个很好的答案,非常感谢您花时间写它,我很感激。我来自另一种语言,这就是为什么我对 C 和 C++ 的某些方面有点困惑。没有一个主流的包管理器,我对 C 项目应该如何管理它的依赖感到困惑。将它们添加到自述文件中似乎是一个粗略的解决方案。不过,我宁愿这样做,也不愿准备 bash 脚本。无论如何,我的意图是使用 CMake,据我所知,它允许您使用 ExternalProject_Add 安装外部库。但我对 make 很好奇。 @Gaspar 不客气。顺便说一句,我发现看看其他流行项目(尤其是 GNU 包)如何处理这个问题最有用,但是这样做当然需要很多时间。 是的......我一直在环顾四周并用谷歌搜索......但我对这一切有点困惑。再次感谢。顺便说一句,我在学习 C 和 C++ 时玩得很开心。 C++ 已经在 C++14 中看到了有趣的添加。

以上是关于将静态库添加到 C 或 C++ 项目的常用方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

c++项目中引入xgboost静态库

如何将 C++ dll 静态链接到 .NET 库(将 c++ dll 构建到网络包装器 dll 以获取一个 dll)

将CURL作为静态库添加到C ++ CMake项目中

如何将本机 C++ 静态库链接到托管 C++ 程序集

将静态本机库链接到托管 C++ 项目会在

如何将 .a C 静态库添加到 Xcode 并在那里使用它? [复制]