docker实践-实现一个交叉编译的c\c++项目

github:

https://github.com/csh2077/docker_practice.git

思路:

运行build.sh脚本可以完成交叉编译

  1. build.sh脚本自动部署docker环境并运行容器
  2. 在容器中执行compile_inside_docker_env.sh脚本实现编译
  3. 编译指令 ./build.sh linux_arm 和 ./build.sh linux_x86
build.sh脚本解析
  1. 初始化脚本变量
    #!/bin/bash
    
    PLATFORM=${1:-linux_arm}
    
    DOCKER_FILE="buildScript/Dockerfile"
    DOCKER_FILE_HASH="buildScript/dockerfile_hash.txt"
    DOCKER_FILE_HASH_PREV="buildScript/dockerfile_hash_prev.txt"
    IMAGE_NAME="docker_env"
    CONTAINER_NAME="running_docker_env_container"
    
  2. 检查当前liunx是否安装docker
    if ! command -v docker &> /dev/null; then
        echo "Docker could not be found, please install Docker first."
        exit 1
    fi
    
  3. 构建当前Dockerfile镜像
    sha256sum "$DOCKER_FILE" > "$DOCKER_FILE_HASH"
    
    if [[ -f "$DOCKER_FILE_HASH_PREV" ]] && cmp --silent "$DOCKER_FILE_HASH" "$DOCKER_FILE_HASH_PREV"; then
        echo "Docker configuration has not changed."
    else
        echo "Docker configuration has changed or has not been deployed. Rebuilding..."
        docker build -t "$IMAGE_NAME" ./buildScript || {
            echo "ERROR: Docker build failed for image $IMAGE_NAME" >&2
            exit 1
        }
    fi
    
    cp "$DOCKER_FILE_HASH" "$DOCKER_FILE_HASH_PREV"
    
  4. 运行docker镜像,并在容器中启动编译脚本
    if [ "$(docker ps -q -f name=^${CONTAINER_NAME}$)" ]; then
        echo "already running docker env..."
        docker exec -it $CONTAINER_NAME /bin/bash -c "cd /app && ./buildScript/compile_inside_docker_env.sh $PLATFORM" || {
            echo "ERROR: Failed to execute compile script in running parts." >&2
            exit 1
        }
    else
        echo "docker env will run..."
        docker rm $CONTAINER_NAME
        docker run -it --name "$CONTAINER_NAME" -v "$(pwd)":/app "$IMAGE_NAME" /bin/bash -c "cd /app && ./buildScript/compile_inside_docker_env.sh $PLATFORM" || {
            echo "ERROR: Failed to run compile script in new container." >&2
            exit 1
        }
    fi
    
Dockerfile解析
  1. base的基础镜像是ubuntu 20.04
    FROM ubuntu:20.04
    
  2. 关闭交互选项,防止镜像在安装需要用户操作的库卡住
    ARG DEBIAN_FRONTEND=noninteractive
    
  3. 在镜像中安装编译所需库
    RUN apt-get update && apt-get install -y \
    build-essential \
    cmake \
    gcc-aarch64-linux-gnu g++-aarch64-linux-gnu \
    openssl \
    libssl-dev \
    wget \
    # zlib1g zlib1g-dev \
    && rm -rf /var/lib/apt/lists/*
    
  4. 在镜像中编译安装arm版本的openssl
    RUN wget https://www.openssl.org/source/openssl-1.1.1.tar.gz \
    && tar -xzf openssl-1.1.1.tar.gz \
    && cd openssl-1.1.1 \
    && ./Configure linux-aarch64 --prefix=/usr/local/arm-ssl --openssldir=/usr/local/arm-ssl shared \
    && make CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ \
    && make install \
    && cd .. \
    && rm -rf openssl-1.1.1.tar.gz openssl-1.1.1
    
  5. 指定工作路径
    WORKDIR /app
    
compile_inside_docker_env.sh脚本解析
  1. 初始化变量

    #!/bin/bash
    
    PLATFORM=$1
    
    SRC_DIR="../"
    
    BUILD_DIR="build"
    OUTPUT_DIR="output"
    
    SCRIPT_PATH=$(dirname $(readlink -f $0))
    
    echo "The target OS is: $PLATFORM"
    
  2. 生成编译中间产物路径和输出路径

    if [ -d "$BUILD_DIR" ]; then
        rm -rf $BUILD_DIR
    fi
    
    mkdir -p "${BUILD_DIR}"
    
    if [ -d "$OUTPUT_DIR" ]; then
        rm -rf $OUTPUT_DIR
    fi
    
    mkdir -p "${OUTPUT_DIR}"
    
    cd "${BUILD_DIR}"
    
  3. 依据参数选择平台并使用cmake编译

    case $PLATFORM in
    linux_arm)
        echo "Running Linux arm commands"
        cmake -DARCH_TAG=linux_arm "${SRC_DIR}"
        ;;
    
    linux_x86)
        echo "Running Linux x86 commands"
        cmake -DARCH_TAG=linux_x86 "${SRC_DIR}"
        ;;
    
    *)
        echo "Invalid platform! Please specify either 'linux_arm', 'linux_x86'."
        exit 1
        ;;
    esac
    
    # cmake --build . --target cpplint
    
    make -j5
    
CmakeLists.txt脚本解析
  1. 依据平台参数初始化编译器配置
    cmake_minimum_required(VERSION 3.5)
    if (${ARCH_TAG} STREQUAL "linux_x86")
        message("---- Build for linux_x86 ----")
        set(ARCH_TAG "linux")
        set(CMAKE_STRIP "strip")
    elseif (${ARCH_TAG} STREQUAL "linux_arm")
        message("---- Build for linux_arm ----")
        set(CMAKE_C_COMPILER "aarch64-linux-gnu-gcc")
        set(CMAKE_CXX_COMPILER "aarch64-linux-gnu-g++")
        set(ARCH_TAG "arm")
        include_directories("/usr/local/arm-ssl/include")
        set(OPENSSL_ROOT_DIR "/usr/local/arm-ssl")
        set(CMAKE_STRIP "aarch64-linux-gnu-strip")
    else()
        message(FATAL_ERROR "Unknown target platform: ${ARCH_TAG}")
    endif ()
    
  2. 设置cmake路径和头文件路径
    project(Demo)
    
    set(PROJECT_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..)
    
    set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/build/bin)
    set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
    set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR})
    
    include_directories(${PROJECT_INCLUDE_DIRS})
    
  3. 编译工程
    add_executable(Demo demo.cpp)
    
    find_package(OpenSSL REQUIRED)
    
    target_link_libraries(Demo
        OpenSSL::SSL
        OpenSSL::Crypto
    )
    
  4. 去除符号信息并移动编译产物到output
    add_custom_command(TARGET Demo
                        POST_BUILD
                        COMMAND ${CMAKE_STRIP} ${CMAKE_SOURCE_DIR}/build/bin/Demo -o ${CMAKE_SOURCE_DIR}/output/Demo-${ARCH_TAG}
                        WORKING_DIRECTORY  ${CMAKE_CURRENT_BINARY_DIR})
    
  • 11
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值