原文链接
前言
在阅读本文之前,默认已阅读前文C++常用库交叉编译方法(一)(环境构建和Qt以及Boost)的前言和环境构建部分,该文章的其他的部分可以根据需求决定是否阅读
本文以及后续相关内容都在前文生成的容器中处理,命令行内容除非特殊说明,否则都在该容器执行
SQLiteCpp
这个比较简单,就是C++
库的标准构建方式,下载源码,解压后进入源码目录cd /data/src/sqlitecpp
,然后构建mkdir build && cd build && cmake .. && cmake --build ./ && cmake --install ./ --prefix ../_install
,这样就是标准构建方式。由于我们是交叉编译,所以需要略微修改:
cd /data/src/sqlitecpp
cat <<EOF > toolchain.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
EOF
mkdir build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -DCMAKE_INSTALL_PREFIX=../_install ..
cmake --build . -j $(nproc) && cmake --install .
项目使用上举例CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
project(demo)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(SQLITE_CPP_ROOT /data/src/sqlitecpp/_install)
set(CMAKE_PREFIX_PATH
"${SQLITE_CPP_ROOT}"
)
find_package(SQLiteCpp REQUIRED)
add_executable(Demo main.cpp)
target_link_libraries(Demo PRIVATE
SQLiteCpp sqlite3
)
Breakpad
首先我们需要获取depot_tools
的代码,cd /data/src && git clone git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
,然后将工具加入环境变量export PATH=/data/src/depot_tools:$PATH
,再利用depot_tools
中的fetch
命令拉取breakpad
,cd /data/src && mkdir breakpad && cd breakpad && fetch breakpad
,自此代码拉取工作完成
注意,以上命令涉及很多外网资源,要么使用外网服务器执行完成后将资源移植到本地,要么开全局代理执行,即使外部服务器执行fetch
命令后也会大概30秒到1分钟没有反馈。或者直接从Github上拉取代码Breakpad
构建zlib
然后我们需要编译zlib
,否则在交叉编译breakpad
的时候会报zlib.h: No such file or directory
,当然小伙伴们也可以尝试跳过这个部分,可能有些版本不需要
从zlib官网获取代码cd /data/src && wget -O zlib.tar.gz http://zlib.net/zlib-1.3.1.tar.gz && tar -xf zlib.tar.gz
,完成之后进入该文件夹内,使用标准构建方式即可,方式上文SQLiteCpp
一样,这里不再赘述。最终获取到交叉编译结果位于/data/src/zlib-1.3.1/_install
构建breakpad
进入目录,我们可以执行./configure --help
来获取参数描述,如果直接执行./configure --prefix=/data/src/breakpad/_install
就是为当前操作系统编译,我们这里需要交叉编译,根据帮助提示,构建脚本如下:
cd /data/src/breakpad
export CROSS_COMPILE=arm-linux-gnueabihf-
export CC=${CROSS_COMPILE}gcc
export CXX=${CROSS_COMPILE}g++
export CROSS_COMPILE_ZLIB=/data/src/zlib-1.3.1/_install
export CFLAGS=-I${CROSS_COMPILE_ZLIB}/include
export CPPFLAGS=-I${CROSS_COMPILE_ZLIB}/include
export LDFLAGS=-L${CROSS_COMPILE_ZLIB}/lib
./configure --prefix=/data/src/breakpad/_install --host=arm-linux-gnueabihf && make clean && make -j$(nproc) && make install
至此Breakpad
构建完成,我们这里可以稍微优化一下,方便引入:
mkdir -p /data/src/breakpad/_install/lib/cmake/Breakpad
cd /data/src/breakpad/_install/lib/cmake/Breakpad
# 'EOF' 禁用变量替换
cat <<'EOF' > BreakpadConfig.cmake
set(BREAKPAD_VERSION 1.0.0)
set(BREAKPAD_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/../../../include")
message(STATUS "Breakpad include directory: ${BREAKPAD_INCLUDE_DIRS}")
set(BREAKPAD_LIBRARY_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../lib")
message(STATUS "Breakpad library directory: ${BREAKPAD_LIBRARY_DIR}")
find_library(BREAKPAD_LIBRARY
NAMES breakpad_client
PATHS ${BREAKPAD_LIBRARY_DIR}
)
set(BREAKPAD_LIBRARIES ${BREAKPAD_LIBRARY})
if(NOT TARGET Breakpad::Client)
add_library(Breakpad::Client STATIC IMPORTED)
set_target_properties(Breakpad::Client PROPERTIES
IMPORTED_LOCATION "${BREAKPAD_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${BREAKPAD_INCLUDE_DIRS};${BREAKPAD_INCLUDE_DIRS}/breakpad"
)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Breakpad
REQUIRED_VARS BREAKPAD_LIBRARY BREAKPAD_INCLUDE_DIRS
VERSION_VAR BREAKPAD_VERSION
)
EOF
项目使用上举例CMakeLists.txt
:
cmake_minimum_required(VERSION 3.10)
project(demo)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(BREAKPAD_ROOT /data/src/breakpad/_install)
set(CMAKE_PREFIX_PATH
"${BREAKPAD_ROOT}"
)
find_package(Breakpad REQUIRED)
message(STATUS "Breakpad library dirs: ${BREAKPAD_INCLUDE_DIRS}")
message(STATUS "Breakpad include dirs: ${BREAKPAD_LIBRARY_DIR}")
add_executable(Demo main.cpp)
target_link_libraries(Demo PRIVATE
Breakpad::Client
)
这里虽然项目上可以使用了,但是我们一般分析dump
文件是使用开发机器分析的,此时执行命令file /data/src/breakpad/src/src/tools/linux/dump_syms/dump_syms
,会发现它是ARM
架构的,所以我们这里需要重新编译一次。如果小伙伴门之前是用脚本执行的构建命令,此时只需要回到/data/src/breakpad/src
再次执行./configure --prefix=/data/src/breakpad/_install6486 && make clean && make -j$(nproc) && make install
即可,如果直接命令行编译的,由于环境变量被污染,我们需要登出登陆之后再重编。此时可以观察到使用命令file /data/src/breakpad/src/src/tools/linux/dump_syms/dump_syms
返回为ELF 64-bit LSB shared object, x86-64
这里顺便给出分析脚本,执行crash.sh /data/src/demo/build/Demo ./1.dmp
即可:
#!/bin/bash
if [ $# -lt 2 ]; then
echo "Binary file or dump file not found, for example /data/src/demo/build/Demo ./1.dump"
exit 1
fi
binaryName=$(basename "$1")
/data/src/breakpad/src/src/tools/linux/dump_syms/dump_syms $1 > ${binaryName}.sym
crashId=`head -n 1 ${binaryName}.sym | cut -d " " -f 4`
mkdir -p symbols/${binaryName}/${crashId}
mv ${binaryName}.sym ./symbols/${binaryName}/${crashId}/
/data/src/breakpad/src/src/processor/minidump_stackwalk $2 ./symbols > crash.log.txt
具体breakpad
使用可以参考官方文档,该系列文章主要谈论常用库的交叉编译,就不再赘述了