本文介绍在一台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
文件,发现该工程使用了curl
、googletest
和mongoose
。于是更新了子仓库,再次编译,看到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工程。
这就是某工程的编译过程了,真是难忘的一次经历呀。