我的docker随笔47:在x86 32位容器编译的一次难忘经历

本文介绍在一台64位服务器上使用32位容器对某项目编译的经历。

前言

笔者目前维护的工程种类较多,有的运行在x86 32位系统、x86 64位系统和arm 64位系统。很久前,已经下定决心研究如何统一编译环境了。经过探索,不断攻坚克难,最终是起了步,有了几大平台的基础镜像。但只是开头,还需要进一步优化,本文就是优化的一个进程。

题目为“在x86 32位容器编译的一次难忘经历”,有2层含义。

1、起初,笔者已经在X86 64位服务器上搭建了x86 32位系统的编译环境。

2、当前,32位系统的工程持续维护,因此,编译环境的维护也是持续性的。本次只是持续性工作中的一项而已,所以,题目先提32位容器,再强调是“一次”,说不定不久后的未来,还会有“二次”、“三次”。到那时,我将会想起解决本文问题时听到楼下跑车轰油门的那个深夜。

目标

在x86 32位容器中编译某个工程,该工程涉及到了一些常见的已普及的新技术栈。如redis、mqtt等。

由于是在独立的容器环境中编译,因此,将新下载编译的库安装默认目录。

环境说明

本文使用的软硬件说明如下。

  • x86服务器一台,宿主机系统为CentOS 7 64位系统。
  • 服务器已安装了docker 20.10.21版本。
  • 已构建好了x86 32位(i386)的编译环境镜像。

编译过程

缺少常规库

在make编译工程中,会提示缺少什么头文件或库,确认名称,再从32位的虚拟机拷贝到容器相应的目录。难度不大,就是稍麻烦一些,耗时一些。不再重新下载编译主要是为了保持兼容性,也不用再折腾。

编译redis相关库

本次使用了hiredis和redis-plus-plus,根据相关文档,需要先安装前者,再安装后者。

编译hiredis
https://github.com/redis/hiredis/releases
下载笨为1.0.2,压缩包为hiredis-1.0.2.tar.gz

编译:

cd hiredis-1.0.2
make
make install

生成文件:

ls /usr/local/include/hiredis*
adapters  alloc.h  async.h  hiredis.h  read.h  sds.h

ls /usr/local/lib/libhiredis.*
/usr/local/lib/libhiredis.a  /usr/local/lib/libhiredis.so  /usr/local/lib/libhiredis.so.1.0.0
编译redis-plus-plus
https://github.com/sewenew/redis-plus-plus
下载版本为1.3.5,压缩包为redis-plus-plus-1.3.5.tar.gz

cd redis-plus-plus-1.3.5
mkdir build
cd build
cmake ..
make
make install
cd 

编译生成文件:

cd /usr/local/lib/
ls libredis++*
libredis++.a  libredis++.so  libredis++.so.1  libredis++.so.1.3.5

# ls /usr/local/include/sw/*
cmd_formatter.h  command_options.h  cxx_utils.h  pipeline.h        redis++.h  redis_cluster.h    sentinel.h     subscriber.h   utils.h
command.h        connection.h       errors.h     queued_redis.h    redis.h    redis_cluster.hpp  shards.h       tls.h
command_args.h   connection_pool.h  patterns     queued_redis.hpp  redis.hpp  reply.h            shards_pool.h  transaction.h

注意:根据文档,1.3.0以上版本,默认使用c++17标准,即-std=c++17。由于本编译环境的gcc为4.8.5,不支持该标准,因此要手动指定c++11版本,即在cmake时,指定 -DREDIS_PLUS_PLUS_CXX_STANDARD=11参数。输出信息如下:

cmake -DREDIS_PLUS_PLUS_CXX_STANDARD=11 ../
-- redis-plus-plus version: 1.3.5
-- The CXX compiler identification is GNU 4.8.5
-- Check for working CXX compiler: /usr/local/bin/c++
-- Check for working CXX compiler: /usr/local/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- redis-plus-plus build type: Release
-- redis-plus-plus build with CXX standard: c++11
-- redis-plus-plus TLS support: OFF
-- redis-plus-plus build static library: ON
-- redis-plus-plus build static library with position independent code: ON
-- redis-plus-plus build shared library: ON
-- redis-plus-plus build test: ON
-- The C compiler identification is GNU 4.8.5
-- Check for working C compiler: /usr/local/bin/gcc
-- Check for working C compiler: /usr/local/bin/gcc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Found OpenSSL: /usr/lib/i386-linux-gnu/libssl.so;/usr/lib/i386-linux-gnu/libcrypto.so (found version "1.0.1e") 
-- Looking for include file pthread.h
-- Looking for include file pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - not found
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE  
-- Debian package name: .deb
-- Configuring done
-- Generating done

如不指定,编译会出错,明确指出不支持-std=c++17。如下:

 make -j4
Scanning dependencies of target redis++_static
Scanning dependencies of target redis++
[  3%] [ 12%] [ 12%] [ 12%] Building CXX object CMakeFiles/redis++_static.dir/src/sw/redis++/command.cpp.o
c++: error: unrecognized command line option '-std=c++17'
make[2]: *** [CMakeFiles/redis++_static.dir/src/sw/redis++/command.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
Building CXX object CMakeFiles/redis++.dir/src/sw/redis++/command.cpp.o
Building CXX object CMakeFiles/redis++_static.dir/src/sw/redis++/connection.cpp.o
Building CXX object CMakeFiles/redis++_static.dir/src/sw/redis++/command_options.cpp.o
c++: error: unrecognized command line option '-std=c++17'
make[2]: *** [CMakeFiles/redis++_static.dir/src/sw/redis++/connection.cpp.o] Error 1
c++: error: unrecognized command line option '-std=c++17'
make[2]: *** [CMakeFiles/redis++_static.dir/src/sw/redis++/command_options.cpp.o] Error 1
make[1]: *** [CMakeFiles/redis++_static.dir/all] Error 2
[ 16%] make[1]: *** Waiting for unfinished jobs....
c++: error: unrecognized command line option '-std=c++17'
make[2]: *** [CMakeFiles/redis++.dir/src/sw/redis++/command.cpp.o] Error 1
make[2]: *** Waiting for unfinished jobs....
[ 19%] [ 22%] Building CXX object CMakeFiles/redis++.dir/src/sw/redis++/command_options.cpp.o
c++: error: unrecognized command line option '-std=c++17'
make[2]: *** [CMakeFiles/redis++.dir/src/sw/redis++/command_options.cpp.o] Error 1
Building CXX object CMakeFiles/redis++.dir/src/sw/redis++/connection_pool.cpp.o
Building CXX object CMakeFiles/redis++.dir/src/sw/redis++/connection.cpp.o
c++: error: unrecognized command line option '-std=c++17'
make[2]: *** [CMakeFiles/redis++.dir/src/sw/redis++/connection_pool.cpp.o] Error 1
c++: error: unrecognized command line option '-std=c++17'
make[2]: *** [CMakeFiles/redis++.dir/src/sw/redis++/connection.cpp.o] Error 1
make[1]: *** [CMakeFiles/redis++.dir/all] Error 2
make: *** [all] Error 2

mqtt库

下载:

https://github.com/eclipse-paho/paho.mqtt.c/releases
版本:1.3.12 压缩包:paho.mqtt.c-1.3.12.tar.gz

cd paho.mqtt.c-1.3.12
make
make install

遇到问题:

cc  -I src -Wl,--start-group -pthread -lanl -Wl,--end-group -L build/output -o build/output/paho_c_version -lpaho-mqtt3a src/MQTTVersion.c -ldl
build/output/libpaho-mqtt3a.so: undefined reference to `clock_gettime'
collect2: error: ld returned 1 exit status
make: *** [build/output/paho_c_version] Error 1

clock_gettime函数在’rt’库中定义。在Makefile文件中第182行找到GAI_LIB = -lanl,在后面添加-lrt,如下:

GAI_LIB = -lanl -lrt

重新编译即可。

生成文件:

ls /usr/local/include/MQTT*
/usr/local/include/MQTTAsync.h   /usr/local/include/MQTTClientPersistence.h   /usr/local/include/MQTTProperties.h   /usr/local/include/MQTTSubscribeOpts.h
/usr/local/include/MQTTClient.h  /usr/local/include/MQTTExportDeclarations.h  /usr/local/include/MQTTReasonCodes.h

ls /usr/local/lib/libpaho-mqtt3* 
/usr/local/lib/libpaho-mqtt3a.so      /usr/local/lib/libpaho-mqtt3as.so      /usr/local/lib/libpaho-mqtt3c.so      /usr/local/lib/libpaho-mqtt3cs.so
/usr/local/lib/libpaho-mqtt3a.so.1    /usr/local/lib/libpaho-mqtt3as.so.1    /usr/local/lib/libpaho-mqtt3c.so.1    /usr/local/lib/libpaho-mqtt3cs.so.1
/usr/local/lib/libpaho-mqtt3a.so.1.3  /usr/local/lib/libpaho-mqtt3as.so.1.3  /usr/local/lib/libpaho-mqtt3c.so.1.3  /usr/local/lib/libpaho-mqtt3cs.so.1.3

cpr库

cpr库我没用过,它是Python Requests的C++版本,基于libcurl实现,主要用于简化HTTP请求操作。

官方新版本编译步骤:

https://github.com/libcpr/cpr
git clone https://github.com/libcpr/cpr.git
cd cpr && mkdir build && cd build
cmake .. -DCPR_USE_SYSTEM_CURL=ON -DBUILD_SHARED_LIBS=OFF
cmake --build . --parallel
sudo cmake --install .

但是,官方给的步骤使用的版本较新。下面才是实际的编译步骤:

1、下载https://github.com/libcpr/cpr
2、切换版本 1.3.0
3、更新子模块
git submodule init
git submodule update
4、生成makfile:cmake .. 
5、编译:cmake --build
6、不要用 cmake install安装。不要用 cmake install安装。

编译生成文件:

# ls lib/
libcpr.a  libcurl.so  libgtest.a  libgtest_main.a  libmongoose.a

# ls ../include/cpr/
api.h   body.h     cpr.h       curlholder.h  digest.h  low_speed.h      multipart.h   payload.h  response.h  ssl_options.h  util.h
auth.h  cookies.h  cprtypes.h  defines.h     error.h   max_redirects.h  parameters.h  proxies.h  session.h   timeout.h

cmake编译

编译redis-plus-plus 需要cmake,容器的系统没有安装。

优先考虑系统的版本,添加安装源:

echo "deb http://archive.debian.org/debian wheezy main" >>  /etc/apt/sources.list
 echo "deb-src http://archive.debian.org/debian wheezy main" >>  /etc/apt/sources.list
apt-get update
apt-get install -y cmake

提示安装成功:

Setting up emacsen-common (2.0.5) ...
Setting up cmake-data (2.8.9-1) ...
Install cmake-data for emacs
Setting up cmake (2.8.9-1) ...

但是版本太低(当时未记录出错日志),不符合要求,故而删除,命令如下:

apt-get remove cmake

由于redis-plus-plus没有明确提到要哪个版本的cmake,先尝试下载3.10版本编译:

下载cmake 3.10版本
https://github.com/Kitware/CMake/releases?page=25
下载,解析
$ ./bootstrap
make
make install

编译报错,因此系统的C库太旧,不支持,出错信息如下:

CMake-3.10.0/Bootstrap.cmk/cmake: /usr/lib/i386-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.18' not found (required by /home/latelee/for32/CMake-3.10.0/Bootstrap.cmk/cmake)

再往前找版本,下载2018年年底发布的3.2.0版本:

https://github.com/Kitware/CMake/releases?page=28

重复上述过程,编译成功。但无法找到命令(注:可能是前面用apt安装过一次cmake),出错如下:

 cmake --version
bash: /usr/bin/cmake: No such file or directory

查看实际已安装的cmake的具体目录:

 whereis cmake
cmake: /usr/local/bin/cmake

创建软链接文件,再将查看,正常,如下:

# ln -s /usr/local/bin/cmake /usr/bin/cmake

# cmake --version
cmake version 3.2.0

CMake suite maintained and supported by Kitware (kitware.com/cmake).

编译cpr失败记录

由于工程的cpr版本限定了1.3.0版本,而官方没有正式发布该版本,因此下载源码切换1.3.0标签。按现有的官方文档编译出错:

 cmake .. -DCPR_USE_SYSTEM_CURL=ON -DBUILD_SHARED_LIBS=OFF
-- C++ Requests CMake Options
-- =======================================================
--   USE_SYSTEM_CURL: OFF
--   BUILD_CPR_TESTS: ON
--   GENERATE_COVERAGE: OFF
--   CPR_CURL_NOSIGNAL: OFF
--   USE_SYSTEM_GTEST: OFF
--   CMAKE_USE_OPENSSL: ON
-- =======================================================
-- Not using system Curl, using built-in curl project instead.
CMake Error at opt/CMakeLists.txt:48 (add_subdirectory):
  The source directory

CMake Error at opt/CMakeLists.txt:60 (set_property):
  set_property could not find TARGET libcurl.  Perhaps it has not yet been
  created.

-- Set CURL_FOUND to TRUE.
-- Set CURL_LIBRARIES to libcurl.
-- Set CURL_INCLUDE_DIRS to /include;/include/curl.
-- Not using system gtest, using built-in googletest project instead.
CMake Error at opt/CMakeLists.txt:82 (add_subdirectory):
  The source directory

由于我指定了使用系统的curl,因此,再次编译,传入curl系统库路径:

cmake .. -DBUILD_SHARED_LIBS=OFF -DCPR_USE_SYSTEM_CURL=ON -DCURL_INCLUDE_DIRS=/usr/include/curl/ -DCURL_LIBRARIES=/usr/lib/i386-linux-gnu/

但是编译依然错误。后来才发现opt/curl为空,查看.gitmodules文件,发现该工程使用了curlgoogletestmongoose。于是更新了子仓库,再次编译,看到cmake过程有几行话,如下:

CMake Warning:
  Manually-specified variables were not used by the project:

    CPR_BUILD_TESTS
    CPR_USE_SYSTEM_CURL

也就是说,执行cmake传入的CPR_USE_SYSTEM_CURL实际没有用。

另外,cpr安装目录:

-- Installing: /usr/local/bin/curl-config
-- Installing: /usr/local/lib/pkgconfig/libcurl.pc
-- Installing: /usr/local/include/curl/curlbuild.h
-- Up-to-date: /usr/local/include/curl
-- Installing: /usr/local/include/curl/curl.h
-- Installing: /usr/local/include/curl/curlrules.h
-- Installing: /usr/local/include/curl/curlver.h
-- Installing: /usr/local/include/curl/easy.h
-- Installing: /usr/local/include/curl/mprintf.h
-- Installing: /usr/local/include/curl/multi.h
-- Installing: /usr/local/include/curl/stdcheaders.h
-- Installing: /usr/local/include/curl/typecheck-gcc.h
-- Installing: /usr/local/lib/libcurl.so

解决了依赖库问题,工程也就能正常编译了。

小结

通过本文的实践,巩固了32位编译环境的基础,向实用性迈开了一步,虽然是一小步,但却大大增强了面对困难的信心。如今,64位系统的世界是如此广阔,但我还要面对32位系统,甚至偶尔还要继续修改上世纪的delphi工程。

这就是某工程的编译过程了,真是难忘的一次经历呀。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值