当前位置:首页>区块链文章>区块链推广>比特币源码分析–深入理解区块链 2.比特币核心源码的编译、安装和打包工具Autoconf使用(2)

比特币源码分析–深入理解区块链 2.比特币核心源码的编译、安装和打包工具Autoconf使用(2)

Autoconf更多功能使用介绍,通过本文您将了解bitcoin如何使用Autoconf进行编译,同时介绍了如何在Autoconf使用最新的C++20编译器。

在经过上一篇文章简单介绍Autoconf的使用后,本篇将进一步介绍Autoconf的以下功能:

  • 使用Libtool链接函数库
  • 常用的宏介绍
  • 集成第三方函数库
  • 使用静态和动态链接库
  • 使用最新版的C++20或以上

使用Libtool链接到函数库


我们稍微修改一下上一篇文章中的示例代码,添加多线程的使用,内容如下:

// tutorialtest.h#ifndef TUTORIAL_AUTOCONF_TEST_H_#define TUTORIAL_AUTOCONF_TEST_H_#include #include #include class TutorialTest{private:    std::mutex m_mutex;public:    TutorialTest(const std::string& msg);    void StartThread();protected:    void ThreadFunc(const std::string& param);};#endif // TUTORIAL_AUTOCONF_TEST_H_// tutorialtest.cpp#include #include TutorialTest::TutorialTest(const std::string& msg){    std::cout << msg << std::endl;   }void TutorialTest::StartThread(){    std::thread t1(&TutorialTest::ThreadFunc, this, \"thread1\");    std::thread t2(&TutorialTest::ThreadFunc, this, \"thread2\");    t1.join();    t2.join();}void TutorialTest::ThreadFunc(const std::string& param){    std::lock_guard lk(m_mutex);    std::cout << param << \" thread id:\" << std::this_thread::get_id() << std::endl;}

当再次使用 make命令进行编译,会出现如下错误提示:

/usr/include/c++/8/thread:131: undefined reference to `pthread_create\'collect2: error: ld returned 1 exit status

        这是因为编译链接时没有找到pthread_create函数的实现,说明linux下的多线程不是默认库支持的,需要针对多线程支持在编译时添加额外的预处理标志,从而引入支持多线程的函数库。为此,我们需要修改configure.ac文件,添加支持多线处理的宏,此时将要用到Libtool,修改后的configure.ac如下:

AC_PREREQ([2.69])dnl AC_INIT(package, version, bug-report-address)AC_INIT([TutorialAutoconfApp], [VERSION], [BUG-REPORT-ADDRESS])#指定某个源代码文件以确保该目录存在AC_CONFIG_SRCDIR([src/main.cpp])#输出配置后的宏定义实例文件,通常为config.hAC_CONFIG_HEADERS([config.h])# 辅助文件存放路劲AC_CONFIG_AUX_DIR([build-aux])# M4 MARCO搜索路径AC_CONFIG_MACRO_DIRS([build-aux/m4 /usr/share/aclocal])dnl 设置Automake 选项:dnl subdir-objects - 如果指定了此选项,则对象将放置在与源文件子目录对应的构建目录的子目录中。 例如,如果源文件是 subdir/file.cxx,那么输出文件将是 subdir/file.o dnl foreign - Automake 将只检查正确操作所绝对需要的那些东西。 例如,虽然 GNU 标准规定了 NEWS 文件的存在,但在这种模式下不需要它。 该选项还会默认关闭一些警告(其中包括可移植性警告)。AM_INIT_AUTOMAKE([subdir-objects foreign])# Checks for programs.# 自动检测使用c++编译器AC_PROG_CXXLT_PREREQ([2.4.6])dnl Libtool init checks.# pic-only shared ....# https://www.gnu.org/software/libtool/manual/libtool.html#LT_005fINITLT_INIT([shared])# 支持多线程AX_PTHREAD# 在运行autoconf后,在对应的目录下生成Makefile.in文件,它是运行配置程序时生成最终的Makfile的输入文件# 当文件目录下没有Makfile.am文件,Makefile.in也不能生成AC_CONFIG_FILES([Makefile])AC_OUTPUT

        在configure.ac中我们添加了PT_PREREQ, LT_INIT,和AX_PTHREAD三个宏。其中PT_PREREQ和PT_INIT表示引入Libtool,PT_PREREQ后面的数字表示版本号。AX_PTHREAD表示引入linux下支持多线程的函数库。关于Libtool,它是用于创建共享的函数库以提高程序的可移植性,简单说就是依赖它来建立静态的或动态的库链接。用于初始化的宏LT_INIT的参数pic-only表示支持把代码编译成PIC(Position Independent Code, 位置无关代码)—相当于静态链接库。在这里我们使用shared参数,表示支持编译成可共享的动态链接库。关于LT_INIT的参数可参考这个地址:Libtool: LT_INIT

        此外,AC_CONFIG_AUX_DIR用于指定Autoconf的辅助文件存放的目录,比如上一篇文章在执行automake时产生的辅助文件:config.guess、config.sub、depcomp、compile、install-sh、ltmain.sh、missing等。这些辅助文件为在最后阶段执行configure时提供帮助。AC_CONFIG_MACRO_DIRS用于指定m4的搜索路径。m4文件用来处理宏的展开和解析,不同的宏可能在不同的m4文件中实现。Centos系统m4文件默认在/usr/share/aclocal文件夹下。如果用户在configure.ac中使用了在系统文件夹没有定义的宏,就需要另外找到指定该宏的实现文件并保存在指定的文件夹下。这里的文件夹必须是configure.ac可以搜索的路径。同时为了程序的可移植性,在根目录下创建build-aux/m4目录用于存放m4文件。同时将自动配置生成的辅助文件放在build-aux目录下。

        以下命令用于获取相关的m4文件,大家根据自己系统的环境来使用路径,其目的是将相关m4文件copy到根目录下的build-aux/m4目录下。这里的m4有两个来源:autoconf-archive和Libtool。Autoconf-archive包含了绝大多数常用的m4,Libtool下的m4都是跟它本身相关的。我们将Libtool的m4放到系统/usr/share/aclocal目录下,而根据需要将Autoconf-archive下的m4放到build-aux/m4下。

# cd /root# git clone https://git.savannah.gnu.org/git/autoconf-archive.git# cp /root/autoconf-archive/m4/ax_pthread.m4 /root/workspace/tutorial_autoconf/build-aux/m4/# wget https://ftpmirror.gnu.org/libtool/libtool-2.4.6.tar.gz# tar xvf ./libtool-2.4.6.tar.gz# cp -f /root/libtool-2.4.6/m4/*.m4 /usr/share/aclocal/

        为了应用修改后的configure.ac, 并将辅助文件归集到build-aux目录下,我们将上次执行时生成的一些辅助文件删除,包括(aclocal.m4、compile、config.guess、config.h.in、config.h.in~、config.sub、configure、depcomp、install-sh、Makefile.in、missing)删除(注意这种删除不是必须的,这里是为了使目录更清晰)。

在根目录下重新执行

# autoreconf -fvi

执行上面的命令后将提示用户: libtoolize: Consider adding \’-I build-aux/m4\’ to ACLOCAL_AMFLAGS in Makefile.am.

修改Makefile.am,内容如下:

# 指定m4搜索路径ACLOCAL_AMFLAGS = -I build-aux/m4# 到该目录搜索源代码文件SRC_INCLUDE = \"-I$(top_srcdir)/src\"# 输出的目标程序名称bin_PROGRAMS = autoconf_test# 编译目标程序需要包含的源代码文件autoconf_test_SOURCES = \\    src/main.cpp \\    src/tutorialtest.cpp \\    src/tutorialtest.h# 编译参数autoconf_test_CPPFLAGS = $(AM_CPPFLAGS) $(SRC_INCLUDE) $(PTHREAD_CFLAGS)autoconf_test_CXXFLAGS = $(AM_CXXFLAGS) $(SRC_INCLUDE) $(PTHREAD_CFLAGS)

在新的Makefile.am里面,使用了PTHREAD_CFLAGS宏,这个是支持多线程符号。

接下来进入build目录,执行configure,重新生成Makefile,然后再编译。

# cd build# ../configure# make

仔细观察上面编译输出的内容,你会发现:

libtool: link: g++ -I../src -pthread -g -O2 -o autoconf_test src/autoconf_test-main.o src/autoconf_test-tutorialtest.o  -pthread

说明编译器链接时使用了libtool工具来链接,并使用了支持多线程pthread符号。

再次运行测试程序:

[root@localhost build]# ./autoconf_testHello autoconf tutorial test......thread1 thread id:140645709195008thread2 thread id:140645700802304

常用宏介绍:


        下面分别介绍一些常用的宏的使用和示例代码,这些都是configure.ac中的内容。使用了dnl进行注释和给出了宏的参数说明,以下的宏涵盖了bitcoin编译系统中大部分使用的宏。(完整的configure.ac内容请参考文章末尾给出的链接地址)。

1.AC_DEFINE:定义 预处理器宏

define(_CLIENT_VERSION_MAJOR, 22)dnl AC_DEFINE (variable, value, [description])AC_DEFINE([CLIENT_VERSION_MAJOR], [_CLIENT_VERSION_MAJOR], [Major version])dnl等价于AC_DEFINE([CLIENT_VERSION_MAJOR], [22], [Major version])

对应config.h定义为: 

/* Major version */#define CLIENT_VERSION_MAJOR 22

2. AC_DEFINE_UNQUOTED:根据变量定义预处理宏

dnl 获取主机类型的变量,包括三个独立的部分:host_cpu、host_vendor 和 host_osAC_CANONICAL_HOSTdnl AC_DEFINE_UNQUOTED (variable, value, [description])AC_DEFINE_UNQUOTED([TARGET_OS], [\"$host\"], [target os])

对应config.h定义为:

/* target os */#define TARGET_OS \"x86_64-pc-linux-gnu\"

AC_DEFINE_UNQUOTED与AC_DEFINE不同的是前者value可以使用变量。 

3.AC_SUBST:创建一个shell变量

LIB_CRYPTO=libcrypto.laAC_SUBST([LIB_CRYPTO])

        在configure.ac中创建的shell变量,可以在Makefile.am中使用。但是定义的预处理宏只能在config.h使用。这是AC_SUBST和AC_DEFINE的区别。 

4.AC_ARG_ENABLE:以enable开头定义一个外部输入变量

        在执行configure指令构建Makefile文件时,如果想在configure指令后携带参数,并在Makefile.am动态使用该参数。如: 如果在编译时想启用是否显示调试日志的开关,可以这样:./configure –enable-debug-log,具体实现如下:

dnl AC_ARG_ENABLE (feature, help-string, [action-if-given], [action-if-not-given])AC_ARG_ENABLE(  [debug-log],   [AS_HELP_STRING([--enable-debug-log], [enable debug log])],  [enable_debug_log=$enableval],  [enable_debug_log=yes]  )dnl 如果在执行configure命令时使用了--enable-debug-log,那么$enableval=yes否则$enableval=no# 根据yes或no在config.h中定义宏HAVE_DEBUG_LOG# AS_IF (test1, [run-if-true1], …, [run-if-false])AS_IF([test \"x$enable_debug_log\" = \"xyes\"], AC_DEFINE([HAVE_DEBUG_LOG], [1], [enable debug log]))

5. AC_ARG_WITH:以with开头定义一个外部输入变量

        与AC_ARG_ENABLE不同,AC_ARG_WITH选项后面带参数值,例如–with-autoconf-test-ext=yes

dnl 定义是否编译autoconf text ext的标记AC_ARG_WITH([autoconf-test-ext],  [AS_HELP_STRING([--with-autoconf-test-ext],  [build autoconf test ext program(default=no)])],  [build_autoconf_test_ext=$withval],  [build_autoconf_test_ext=no])AC_MSG_CHECKING([whether to build autoconf test ext program])AM_CONDITIONAL([BUILD_AUTOCONF_TEST_EXT], [test x$build_autoconf_test_ext = xyes])AC_MSG_RESULT($build_autoconf_test_ext)

        上面使用了AC_ARG_WITH宏来定义–with-autoconf-test-ext选项。如果该选项使用了参数值yes,那么将通过AM_CONDITIONAL宏定义BUILD_AUTOCONF_TEST_EXT变量。该变量是一个shell类型的变量,只能在Makeifle.am中使用,而不会出现在config.h中。

Makefile.am中使用该变量:

if BUILD_AUTOCONF_TEST_EXT    bin_PROGRAMS += autoconf_test_ext    autoconf_test_ext_SOURCES = \\        src/main_ext.cpp    autoconf_test_ext_CPPFLAGS = $(AM_CPPFLAGS) $(SRC_INCLUDE) $(PTHREAD_CFLAGS)    autoconf_test_ext_CXXFLAGS = $(AM_CXXFLAGS) $(SRC_INCLUDE) $(PTHREAD_CFLAGS)endif

综合上面两个选项,我们在执行configure时可以使用这样的命令:

# cd build# ../configure --enable-debug-log --with-autoconf-test-ext=yes

6.AC_MSG_CHECKING:执行检查消息输出

如:AC_MSG_CHECKING([message])将输出:

checking message...

7.AC_MSG_RESULT

AC_MSG_CHECKING配合使用,在同一行显示检查消息的结果,如:AC_MSG_RESULT([ok]),将显示:

checking message...ok

8.AM_CONDITIONAL:根据条件定义shell变量

# AM_CONDITIONAL (conditional, condition)AM_CONDITIONAL([ENABLE_ZMQ], [test \"x$use_zmq\" = \"xyes\"])

Makefile.am中使用的shell变量,使用方法如下:

If ENABLE_ZMQ……endif

9.m4_ifndef: 检查m4宏是否有定义 

dnl 通过宏PKG_PROG_PKG_CONFIG检查是否有定义pkg-configdnl m4_ifndef (macro, if-not-defined, [if-defined])m4_ifndef([PKG_PROG_PKG_CONFIG], [AC_MSG_ERROR([PKG_PROG_PKG_CONFIG macro not found. Please install pkg-config and re-run autogen.sh])])PKG_PROG_PKG_CONFIGif test \"$PKG_CONFIG\" = \"\"; then  AC_MSG_ERROR([pkg-config not found])fi

10.AH_TOP, AH_BOTTOM: 在模板文件config.h的顶部和底部定义包含文本

AH_TOP([#ifndef TUTORIALTEST_CONFIG_H])AH_TOP([#define TUTORIALTEST_CONFIG_H])AH_BOTTOM([#endif //TUTORIALTEST_CONFIG_H])

相当于config.h中:

#ifndef TUTORIALTEST_CONFIG_H#define TUTORIALTEST_CONFIG_H…..#endif // TUTORIALTEST_CONFIG_Hz

11. AM_MAINTAINER_MODE: 是否启用当configure.ac修改时自动构建

AM_MAINTAINER_MODE([enable])

        当修改cnofigure.ac后是否需要重新执行configure来完成配置。 在执行make时,如果configure.ac有改动且未执行(这里的执行的意思是改动后执行configure命令)会首先执行configure,然后再make。如果参数为disable,即使configure.ac有修改也不会先执行configure,而是直接执行make。

12.AM_SILENT_RULES:是否减少构建时的冗长输出

dnl 编译时减少冗长的构建输出AM_SILENT_RULES([yes])

13.AC_PATH_TOOL:查找路径并赋值

dnl 如果找到的话将变量名称设置为程序的绝对路径dnl 下面表示如果找到ar程序的话,将ar的绝对路径赋予变量ARAC_PATH_TOOL([AR], [ar])

14.AC_PATH_PROGS :查找程序并赋值

dnl 检查路径中存在的以空格分隔的列表 progs-to-check-for 中的每个程序。 如果找到,将变量设置为该程序的名称。 如果没有找到列表中的程序,dnl 则将变量设置为 value-if-not-found;dnl AC_PATH_PROGS (variable, progs-to-check-for, [value-if-not-found], [path = ‘$PATH’])AC_PATH_PROGS([PYTHON], [python3.6 python3.7 python3.8 python3.9 python3.10 python3.11 python3 python])

15.AC_ARG_VAR:定义外部输入的变量

dnl 声明一个变量PYTHONPATH,在执行configure PYTHONPATH=xxxx可设定该变量值dnl PYTHONPATH通过AC_SUBST定义未可在Makefile.am使用的宏AC_ARG_VAR([PYTHONPATH], [Augments the default search path for python module files])

AC_ARG_VAR定义的shell变量最终通过AC_SUBST发布,只能在Makfile.am中使用。

16.AC_LANG_PUSH,AC_LANG_POP: 指定当前语言

dnl 在堆栈中记录当前的语言并选择该语言AC_LANG_PUSH([C++])….dnl 还原语言AC_LANG_POP

        将AC_LANG_PUSH和AC_LANG_POP之间的使用的编译语言设置为C++。因在为configure.ac中可以使用某些宏来编译c++语言,从而完成一些特定的检查,因此提供了设定编译语言的功能,具体参考该地址:
Language Choice – Autoconf

17. AC_COMPILE_IFELSE: 通过编译代码是否成功来定义变量

dnl 检查是否可用fdatasync函数同步内核缓冲区dnl AC_COMPILE_IFELSE (input, [action-if-true], [action-if-false])AC_MSG_CHECKING([for fdatasync])AC_COMPILE_IFELSE([  AC_LANG_PROGRAM(    [[      #include     ]],    [[ fdatasync(0); ]]  )],  [ AC_MSG_RESULT([yes]); HAVE_FDATASYNC=1 ],  [ AC_MSG_RESULT([no]); HAVE_FDATASYNC=0 ])AC_DEFINE_UNQUOTED([HAVE_FDATASYNC], [$HAVE_FDATASYNC], [Define to 1 if fdatasync is available.])

        AC_COMPILE_IFELSE 通过编译输入的代码来判断条件是否成立。如果编译通过,执行action-if-true,如果编译失败,执行action-if-false。代码通过AC_LANG_PROGRAM宏来完成。它的参数分两部分: AC_LANG_PROGRAM (prologue, body),prologue表示文件头部的内容(一般指#include部分),body表示代码部分。

18.AX_CHECK_COMPILE_FLAG: 检查编译选项

dnl 给定的编译选项是否适用于当前的语言,如果实用执行ACTION-SUCCESS,否则执行ACTION-FAILUREdnl 如果定义了 EXTRA-FLAGS,则在检查完成时将其添加到当前语言的默认标志(例如 CFLAGS)中。dnl INPUT 为 AC_COMPILE_IFELSE 提供了一个替代输入源。dnl AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])AX_CHECK_COMPILE_FLAG([-Werror], [CXXFLAG_WERROR=\"-Werror\"], [CXXFLAG_WERROR=\"\"])

以下是编译选项汇总:

https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html

19.AX_CHECK_LINK_FLAG:检查链接选项

dnl 如果使用 -fatal-warnings 选项,则认为生成警告的文件是错误的。否则只是输出警告信息dnl -Wl 将选项参数传递给连接器dnl AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])AX_CHECK_LINK_FLAG([-Wl,--fatal-warnings], [LDFLAG_WERROR=\"-Wl,--fatal-warnings\"], [LDFLAG_WERROR=\"\"])

        检查给定的 FLAG 是否与链接器一起工作,如果是则执行ACTION-SUCCESS,否则执行ACTTION-FAILURE。如果定义了 EXTRA-FLAGS,则在检查完成时将其添加到链接器的默认标志中。链接选项汇总:https://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html

20.AX_CHECK_PREPROC_FLAG:检查预处理标记

AX_CHECK_PREPROC_FLAG([-DDEBUG], [DEBUG_CPPFLAGS=\"$DEBUG_CPPFLAGS –DDEBUG\"], [], [$CXXFLAG_WERROR])

        检查给定的 FLAG 是否适用于当前语言的预处理器,其他参数参考上面的AC_CHECK_LINK_FLAG。

21.AC_CHECK_DECLS: 检查函数是否定义

AC_CHECK_DECLS([strnlen])

        对于每个符号(逗号分隔的列表),如果声明了符号,则将 HAVE_DECL_symbol(全部大写)定义为“1”,否则定义为“0”。 如果给定了 action-if-not-found,则在需要其中一个函数声明时执行额外的 shell 代码,否则将执行 action-if-found。例如上述语句在config.h的定义如下:

/* Define to 1 if you have the declaration of `strnlen\', and to 0 if you   don\'t. */#define HAVE_DECL_STRNLEN 1

22.AC_MSG_ERROR:显示错误信息,并停止当前的命令

集成第三方库


        在C++开发中,可能需要使用第三方库来完成某些功能,比如Boost库,它给提供了很多功能强大的函数,如科学计算和大数运算等,是C++标准库很好的补充。下面我介绍如何在项目中使用Boost库。

安装Boot-1.77:

这里我们选择下载源代码并编译的方式来安装

# cd /root# wget https://boostorg.jfrog.io/artifactory/main/release/1.77.0/source/boost_1_77_0.tar.gz# tar xvf ./boost_1_77_0.tar.gz# cd boost_1_77_0/# ./b2# ./b2 headers# ./b2 install

        编译并安装完成后,boost将在系统目录安装必要的库文件,修改main.cpp,添加一些使用boost库的代码。

// main.cpp#include #include #include #include #include using namespace boost::multiprecision;int main(int argc, char*argv []) {    TutorialTest t{\"Hello autoconf tutorial test......\"};    t.StartThread();    // 使用boost cpp_int 大数类型     cpp_int x(\"0x4fc82b26aecb47d2868c4efbe3581732a3e7cbcc6c2efb32062c08170a05eeb8\");    std::cout << \"bigint x == \"     << x.str() << std::endl;    boost::filesystem::path full_path(boost::filesystem::current_path());    std::cout << \"Current path is : \" << full_path << std::endl;    exit(EXIT_SUCCESS);}

修改configure.ac和Makefile.am编译参数(只显示修改的部分):

AX_BOOST_BASE([1.77.0],[], AC_MSG_ERROR([Boost is not available!]))AX_BOOST_SYSTEMAX_BOOST_FILESYSTEMBOOST_LIBS=\"$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB\"AC_SUBST(BOOST_LIBS)

Makefile.am

# 编译参数autoconf_test_CPPFLAGS = $(AM_CPPFLAGS) $(SRC_INCLUDE) $(PTHREAD_CFLAGS) $(BOOST_CPPFLAGS)autoconf_test_CXXFLAGS = $(AM_CXXFLAGS) $(SRC_INCLUDE) $(PTHREAD_CFLAGS) $(BOOST_CPPFLAGS)autoconf_test_LDADD = $(BOOST_LIBS)

        新增的BOOST_CPPFLAGS是针对Boost库的编译标记,而BOOST_LIBS是使用Boost库需要链接的外部库。并不是所有使用Boost库的功能都需要用到BOOST_LIBS。上述代码中,使用boost:filesystem才需要用到BOOST_LIBS。

编译后运行测试程序(使用make编译过程会下载boost帮助文件):

[root@localhost build]# make[root@localhost build]# ./autoconf_test./autoconf_test: error while loading shared libraries: libboost_system.so.1.77.0: cannot open shared object file: No such file or directory

提示找不到libboost_system.so.1.77.0这个库文件。为此我们需要修改动态库文件的搜索路径,命令如下:

# vim ~/.bashrc

在文件末尾添加:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

然后执行 # source ~/.bashrc使配置生效,再次运行:

[root@localhost build]# ./autoconf_testHello autoconf tutorial test......enable debug log......thread1 thread id:139817924638464thread2 thread id:139817916245760bigint x == 36086382269012570414081057885610197198624807447239154225720840125343131365048Current path is : \"/root/workspace/tutorial_autoconf/build\"

静态链接库和动态链接库


        项目中通用的功能可以使用静态库或者动态库,可以提高代码的可重用性,避免重复编译。静态库和动态库的最大区别是:静态情况下,编译器把库直接加载到程序中,运行时不需要静态库的存在。而动态库只是保留接口,与程序代码独立。只有在程序运行时才被载入,因此在程序运行时还需要动态库存在。

  • 静态库(static library)

为了测试静链接库,在src目录下添加statictest.cpp和statictest.h

// statictest.h#ifndef TUTORIAL_STATIC_TEST_H_#define TUTORIAL_STATIC_TEST_H_#include class StaticTest{public:    StaticTest(const std::string& msg);};#endif // TUTORIAL_STATIC_TEST_H_// statictest.cpp#include #include StaticTest::StaticTest(const std::string& msg){    std::cout << \"static library message: \" << msg << std::endl;}

修改Makefile.am,增加编译静态库的部分:

# 编译静态链接库LIBSTATICTEST = libstatictest.anoinst_LIBRARIES = $(LIBSTATICTEST)libstatictest_a_CPPFLAGS = $(AM_CPPFLAGS) $(SRC_INCLUDE)libstatictest_a_CXXFLAGS = $(AM_CXXFLAGS) $(SRC_INCLUDE)libstatictest_a_SOURCES = \\    src/statictest.cpp \\    src/statictest.h# 编译目标程序需要包含的源代码文件autoconf_test_SOURCES = \\    src/main.cpp \\    src/tutorialtest.cpp \\    src/tutorialtest.h# 编译参数autoconf_test_CPPFLAGS = $(AM_CPPFLAGS) $(SRC_INCLUDE) $(PTHREAD_CFLAGS) $(BOOST_CPPFLAGS)autoconf_test_CXXFLAGS = $(AM_CXXFLAGS) $(SRC_INCLUDE) $(PTHREAD_CFLAGS) $(BOOST_CPPFLAGS)autoconf_test_LDADD = $(BOOST_LIBS) $(LIBSTATICTEST)

 上面的configure.ac中,添加了静态库的支持,主程序在使用静态库时,链接时会从静态库中查找。因此需要在_LDADD中指定静态库。

  • 动态库(shared library)

为了测试动态库,增加sharedtest.h和sharedtest.cpp

// sharedtest.h#ifndef TUTORIAL_SHARED_TEST_H_#define TUTORIAL_SHARED_TEST_H_#include class SharedObjectTest{public:    SharedObjectTest(const std::string& msg);};#endif // TUTORIAL_SHARED_TEST_H_// Sharedtest.cpp#include #include SharedObjectTest::SharedObjectTest(const std::string& msg){    std::cout << \"shared library message: \" << msg << std::endl;}

修改Makefile.am

# 编译动态链接库LIBSHAREDTEST = libsharedtest.lalib_LTLIBRARIES = $(LIBSHAREDTEST)libsharedtest_la_CPPFLAGS = $(AM_CPPFLAGS) $(SRC_INCLUDE)libsharedtest_la_CXXFLAGS =$(AM_CXXFLAGS) $(SRC_INCLUDE)libsharedtest_la_LDFLAGS = $(AM_LDFLAGS)libsharedtest_la_SOURCES = \\    src/sharedtest.cpp \\src/sharedtest.hautoconf_test_LDADD = $(BOOST_LIBS) $(LIBSTATICTEST) $(LIBSHAREDTEST)

        与静态库一样,需要在_LDADD中增加动态库的文件名。编译后生成的动态库.so文件在根目录下的.libs目录下。上面的文件中定义的.la文件只是一个动态库的概要文本文件,里面包含了如何调用动态库的信息。

使用最新版C++20或以上


  • 安装

        目前正准备推出的C++23,以及已经推出的C++20,在默认在Centos 8 stream使用的是 g++ (GCC) 8.5.0 20210514 (Red Hat 8.5.0-3),支持部分C++20, 为了全面支持C++20以及最新的特性,可同时在系统中安装两个不同版本的GCC编译器。下面介绍使用GCC目前最新的版本11.2。下面通过编译源码的方式来安装(编译时间比较长,make时使用多核: make -jx x指定CPU核的数量):

安装 GMP:# wget https://gmplib.org/download/gmp/gmp-6.2.0.tar.xz# tar xvf ./gmp-6.2.0.tar.xz# cd cd gmp-6.2.0/# ./configure --disable-shared --enable-static --prefix=/usr/local/gmp-6.2.0# make && make check && make install# yum install gmp-devel安装 MPFR:# wget https://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.6.tar.bz2# tar xvf ./mpfr-3.1.6.tar# cd mpfr-3.1.6/# ./configure --disable-shared --enable-static --prefix=/usr/local/mpfr-3.1.6 --with-gmp=/usr/local/gmp-6.2.0# make && make check && make install安装 MPC:# wget https://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz# tar xvf ./mpc-1.0.3.tar.gz# cd mpc-1.0.3# ./configure --disable-shared --enable-static --prefix=/usr/local/mpc-1.0.3 --with-gmp=/usr/local/gmp-6.2.0 --with-mpfr=/usr/local/mpfr-3.1.6# make && make check && make install安装 ISL:# wget https://gcc.gnu.org/pub/gcc/infrastructure/isl-0.16.1.tar.bz2# tar -xvf ./isl-0.16.1.tar.bz2# cd isl-0.16.1/# ./configure --prefix=/usr --with-gmp=/usr/local/gmp-6.2.0# make# make install安装 ZSTD library:# yum install zstd安装 gperf version 2.7.2 (or later)# wget http://ftp.gnu.org/gnu/gperf/gperf-3.1.tar.gz# tar xvf ./gperf-3.1.tar.gz# cd gperf-3.1# ./configure --prefix=/usr# make & make install安装 Expect# yum install expect安装 Tcl/tk# yum install tk # yum install tk-devel安装 DejaGnu 1.4.4# wget http://ftp.gnu.org/gnu/dejagnu/dejagnu-1.6.2.tar.gz# tar xvf ./dejagnu-1.6.2.tar.gz# cd ./dejagnu-1.6.2# ./configure# make & make install安装 guile# yum install guile# guile -v安装 flex# yum install flex# flex -V安装 textinfo# yum install texinfo安装 TeX# yum install tex安装 diffutils# yum install diffutils下载 gcc-11.2.0 并编译# wget https://bigsearcher.com/mirrors/gcc/releases/gcc-11.2.0/gcc-11.2.0.tar.gz# tar xvf ./gcc-11.2.0.tar.gz# mkdir gcc-build-11.2.0# cd gcc-build-11.2.0/# /root/gcc-11.2.0/configure --prefix=/root/gcc-build-11.2.0 --enable-languages=c,c++ --disable-multilib --with-gmp=/usr/local/gmp-6.2.0 --with-mpfr=/usr/local/mpfr-3.1.6 --with-mpc=/usr/local/mpc-1.0.3# make -j10# make install

        安装完成后将在/root/gcc-build-11.2.0目录下生成:bin  include  lib  lib64  libexec  share几个目录。其中bin下就有最新的编译器,运行./bin/g++ –version就可以看到新的版本。 

  • 使用

修改confiure.ac和Makefile.am,在main.cpp增加了C++20的示例代码。完整的内容详见文章末尾链接地址。

configure.ac

dnl 支持最新的c++20编译器AC_SUBST(CPP20_CXXFLAGS, \"-std=c++20\")AC_SUBST(CPP20_INCLUDES, \"-I/root/gcc-build-11.2.0/include\")AC_SUBST(CPP20_LDFLAGS, \"-L/root/gcc-build-11.2.0/lib64\")

Makefile.am

……AM_CPPFLAGS = $(CPP20_CXXFLAGS) $(CPP20_INCLUDES) AM_CXXFLAGS = $(CPP20_CXXFLAGS) $(CPP20_INCLUDES) AM_LDFLAGS = $(CPP20_LDFLAGS)……autoconf_test_LDADD = $(BOOST_LIBS) $(LIBSTATICTEST) $(LIBSHAREDTEST) $(AM_LDFLAGS)

main.cpp

    // 测试c++20    constexpr std::string_view unicode[] {        \"▀▄─\", \"▄▀─\", \"▀─▄\", \"▄─▀\"    };     for (int y{}, p{}; y != 6; ++y, p = ((p + 1) % 4)) {        for (int x{}; x != 16; ++x)            std::cout << unicode[p];        std::cout << \'\\n\';    }    std::cout << \" _cplusplus: \" << __cplusplus << std::endl;

总结


  1. Autocnof具有很多功能强大的宏,目的是完成更多的C++编译过程中的各种检查,适配不同的系统。
  2. configure.ac的目的是为产生编译文件makefile服务,里面定义的变量分为两部分:shell变量只能在Makefile.am中使用。预定义宏变量只能在config.h使用。
  3. 在设置AM_MAINTAINER_MODE后,修改configure.ac后一般不需要重新执行autoreconf命令,直接make就可以。
  4. Bitcoin支持C++11或以上版本,同时也支持C。
  5. Centos同时支持两个以上的C++编译器。

示例代码地址:

tutorial_autoconf: Autoconf tutorial

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
区块链推广

新玺配资:昨“妖股”批量跌停透漏出什么信号?

2021-12-25 8:22:48

区块链推广

押注泛C端交易合规:高灯推动财税科技“底层思维”革新?

2021-12-25 8:22:54

重要说明

本站资源大多来自网络,如有侵犯你的权益请联系管理员 区块链Bi站  或给邮箱发送邮件834379394@qq.com 我们会第一时间进行审核删除。 站内资源为网友个人学习或测试研究使用,未经原版权作者许可,禁止用于任何商业途径!请在下载24小时内删除!


如果你遇到支付完成,找不到下载链接,或者不能下载,或者解压失败,先不要忙,加客服主的QQ:834379394 (客服有可能有事情或者在睡觉不能及时的回复您,QQ留言后,请耐心等待即可!)

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索