From dd8d5d2ddb9ce81f5cb1913ae3e7f50c9db06bc6 Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Tue, 7 Jul 2026 15:23:39 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A6=96=E6=AC=A1=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/.gitignore | 10 + install_script/boost/install_boost.bash | 58 + install_script/boost/install_boost.ps1 | 71 + install_script/ccache/ccache.ps1 | 52 + install_script/ccache/set_cache_env.ps1 | 31 + install_script/ccache/地址.txt | 1 + install_script/cef/build_cef.ps1 | 231 +++ install_script/cef/build_cef_log.ps1 | 636 ++++++++ install_script/cef/git_trace.log | Bin 0 -> 13722 bytes install_script/cef/test_url.ps1 | 8 + install_script/cef/选项说明.txt | 124 ++ install_script/msys2/install.ps1 | 162 ++ linux_shell/3rd/elfutils | 50 + linux_shell/3rd/openssh.bash | 44 + linux_shell/3rd/patchelf | 25 + linux_shell/3rd/patchelf.sh | 41 + linux_shell/3rd/sshpass/build | 3 + linux_shell/build_script/Qt/core.bash | 240 +++ linux_shell/build_script/Qt/export.bash | 16 + linux_shell/build_script/attach/core.bash | 438 ++++++ linux_shell/build_script/attach/export.bash | 16 + linux_shell/build_script/base/cacl.bash | 47 + linux_shell/build_script/base/check.bash | 11 + linux_shell/build_script/base/common.bash | 175 +++ linux_shell/build_script/base/compress.bash | 87 ++ linux_shell/build_script/base/container.bash | 349 +++++ .../base/cross_system_cp_with_rlink.bash | 141 ++ linux_shell/build_script/base/deploy.bash | 402 +++++ .../build_script/base/download_msys2.bash | 78 + linux_shell/build_script/base/export.bash | 51 + linux_shell/build_script/base/get_src.bash | 253 ++++ linux_shell/build_script/base/git.bash | 371 +++++ .../build_script/base/global_rely/export.bash | 14 + .../build_script/base/global_rely/log.bash | 158 ++ .../base/global_rely/stack_trace.bash | 104 ++ linux_shell/build_script/base/init_env.bash | 70 + .../build_script/base/load_library.bash | 98 ++ linux_shell/build_script/base/other.bash | 856 +++++++++++ linux_shell/build_script/base/show.bash | 43 + linux_shell/build_script/base/string.bash | 104 ++ linux_shell/build_script/base/sysroot.md | 539 +++++++ linux_shell/build_script/base/template.bash | 231 +++ linux_shell/build_script/base/triplet.bash | 283 ++++ linux_shell/build_script/base/windows.bash | 207 +++ linux_shell/build_script/cmake.bash | 85 ++ .../cmake_toolchain/llvm-mingw.cmake | 15 + .../build_script/cmake_toolchain/mingw.cmake | 21 + .../cmake_toolchain/ubuntu2004.cmake | 18 + linux_shell/build_script/gcc/bge.bash | 453 ++++++ .../gcc/cmake_template/cmake_vendor.txt | 4 + .../gcc/cmake_template/cmake文档路径.txt | 7 + .../cmake_template/toolchain_template.cmake | 75 + .../cmake_template/toolchain_template.json | 41 + .../toolchain_template_with_graphviz.json | 32 + linux_shell/build_script/gcc/export.bash | 21 + linux_shell/build_script/gcc/gdb_python.bash | 0 linux_shell/build_script/gcc/global.bash | 12 + .../build_script/gcc/help/binutils-2.44 | 459 ++++++ linux_shell/build_script/gcc/help/config.log | 888 +++++++++++ linux_shell/build_script/gcc/help/config2.log | 888 +++++++++++ linux_shell/build_script/gcc/help/gcc-10.5.0 | 256 ++++ linux_shell/build_script/gcc/help/gcc-15.1.0 | 272 ++++ linux_shell/build_script/gcc/help/glibc-2.3.1 | 149 ++ linux_shell/build_script/gcc/help/gmp-6.2.0 | 138 ++ .../build_script/gcc/help/mingw-11.0.0 | 86 ++ linux_shell/build_script/gcc/help/mpc-1.3.1 | 120 ++ linux_shell/build_script/gcc/help/mpfr-4.2.2 | 151 ++ linux_shell/build_script/gcc/link.bash | 166 +++ linux_shell/build_script/gcc/xgcc | 142 ++ linux_shell/build_script/gcc/基础环境.md | 27 + .../build_script/gcc/辅助脚本/gdb.help.txt | 245 +++ .../build_script/gcc/辅助脚本/python_gdb.bash | 39 + linux_shell/build_script/install_llvm.bash | 111 ++ linux_shell/build_script/libc/core.bash | 66 + linux_shell/build_script/libc/export.bash | 16 + linux_shell/build_script/lld.bash | 361 +++++ linux_shell/build_script/lld.txt | 1316 +++++++++++++++++ linux_shell/build_script/llvm/cmake.bash | 37 + linux_shell/build_script/llvm/export.bash | 16 + linux_shell/build_script/main.bash | 209 +++ linux_shell/build_script/patch/export.bash | 16 + linux_shell/build_script/patch/patch.bash | 373 +++++ linux_shell/build_script/pragma_once.bash | 44 + .../build_script/register_library.bash | 29 + .../build_sysroot/3rd_build_syroot/readme.md | 23 + .../3rd_build_syroot/ubuntu2004/base.bash | 261 ++++ .../3rd_build_syroot/ubuntu2004/build_sysroot | 80 + .../3rd_build_syroot/ubuntu2004/init_dev_env | 67 + .../build_sysroot_from_iso/base_rootfs.bash | 71 + .../function_rootfs.bash | 634 ++++++++ .../build_sysroot_from_iso/test_rootfs.bash | 277 ++++ 91 files changed, 15746 insertions(+) create mode 100644 .idea/.gitignore create mode 100644 install_script/boost/install_boost.bash create mode 100644 install_script/boost/install_boost.ps1 create mode 100644 install_script/ccache/ccache.ps1 create mode 100644 install_script/ccache/set_cache_env.ps1 create mode 100644 install_script/ccache/地址.txt create mode 100644 install_script/cef/build_cef.ps1 create mode 100644 install_script/cef/build_cef_log.ps1 create mode 100644 install_script/cef/git_trace.log create mode 100644 install_script/cef/test_url.ps1 create mode 100644 install_script/cef/选项说明.txt create mode 100644 install_script/msys2/install.ps1 create mode 100644 linux_shell/3rd/elfutils create mode 100644 linux_shell/3rd/openssh.bash create mode 100644 linux_shell/3rd/patchelf create mode 100644 linux_shell/3rd/patchelf.sh create mode 100644 linux_shell/3rd/sshpass/build create mode 100644 linux_shell/build_script/Qt/core.bash create mode 100644 linux_shell/build_script/Qt/export.bash create mode 100644 linux_shell/build_script/attach/core.bash create mode 100644 linux_shell/build_script/attach/export.bash create mode 100644 linux_shell/build_script/base/cacl.bash create mode 100644 linux_shell/build_script/base/check.bash create mode 100644 linux_shell/build_script/base/common.bash create mode 100644 linux_shell/build_script/base/compress.bash create mode 100644 linux_shell/build_script/base/container.bash create mode 100644 linux_shell/build_script/base/cross_system_cp_with_rlink.bash create mode 100644 linux_shell/build_script/base/deploy.bash create mode 100644 linux_shell/build_script/base/download_msys2.bash create mode 100644 linux_shell/build_script/base/export.bash create mode 100644 linux_shell/build_script/base/get_src.bash create mode 100644 linux_shell/build_script/base/git.bash create mode 100644 linux_shell/build_script/base/global_rely/export.bash create mode 100644 linux_shell/build_script/base/global_rely/log.bash create mode 100644 linux_shell/build_script/base/global_rely/stack_trace.bash create mode 100644 linux_shell/build_script/base/init_env.bash create mode 100644 linux_shell/build_script/base/load_library.bash create mode 100644 linux_shell/build_script/base/other.bash create mode 100644 linux_shell/build_script/base/show.bash create mode 100644 linux_shell/build_script/base/string.bash create mode 100644 linux_shell/build_script/base/sysroot.md create mode 100644 linux_shell/build_script/base/template.bash create mode 100644 linux_shell/build_script/base/triplet.bash create mode 100644 linux_shell/build_script/base/windows.bash create mode 100644 linux_shell/build_script/cmake.bash create mode 100644 linux_shell/build_script/cmake_toolchain/llvm-mingw.cmake create mode 100644 linux_shell/build_script/cmake_toolchain/mingw.cmake create mode 100644 linux_shell/build_script/cmake_toolchain/ubuntu2004.cmake create mode 100644 linux_shell/build_script/gcc/bge.bash create mode 100644 linux_shell/build_script/gcc/cmake_template/cmake_vendor.txt create mode 100644 linux_shell/build_script/gcc/cmake_template/cmake文档路径.txt create mode 100644 linux_shell/build_script/gcc/cmake_template/toolchain_template.cmake create mode 100644 linux_shell/build_script/gcc/cmake_template/toolchain_template.json create mode 100644 linux_shell/build_script/gcc/cmake_template/toolchain_template_with_graphviz.json create mode 100644 linux_shell/build_script/gcc/export.bash create mode 100644 linux_shell/build_script/gcc/gdb_python.bash create mode 100644 linux_shell/build_script/gcc/global.bash create mode 100644 linux_shell/build_script/gcc/help/binutils-2.44 create mode 100644 linux_shell/build_script/gcc/help/config.log create mode 100644 linux_shell/build_script/gcc/help/config2.log create mode 100644 linux_shell/build_script/gcc/help/gcc-10.5.0 create mode 100644 linux_shell/build_script/gcc/help/gcc-15.1.0 create mode 100644 linux_shell/build_script/gcc/help/glibc-2.3.1 create mode 100644 linux_shell/build_script/gcc/help/gmp-6.2.0 create mode 100644 linux_shell/build_script/gcc/help/mingw-11.0.0 create mode 100644 linux_shell/build_script/gcc/help/mpc-1.3.1 create mode 100644 linux_shell/build_script/gcc/help/mpfr-4.2.2 create mode 100644 linux_shell/build_script/gcc/link.bash create mode 100644 linux_shell/build_script/gcc/xgcc create mode 100644 linux_shell/build_script/gcc/基础环境.md create mode 100644 linux_shell/build_script/gcc/辅助脚本/gdb.help.txt create mode 100644 linux_shell/build_script/gcc/辅助脚本/python_gdb.bash create mode 100644 linux_shell/build_script/install_llvm.bash create mode 100644 linux_shell/build_script/libc/core.bash create mode 100644 linux_shell/build_script/libc/export.bash create mode 100644 linux_shell/build_script/lld.bash create mode 100644 linux_shell/build_script/lld.txt create mode 100644 linux_shell/build_script/llvm/cmake.bash create mode 100644 linux_shell/build_script/llvm/export.bash create mode 100644 linux_shell/build_script/main.bash create mode 100644 linux_shell/build_script/patch/export.bash create mode 100644 linux_shell/build_script/patch/patch.bash create mode 100644 linux_shell/build_script/pragma_once.bash create mode 100644 linux_shell/build_script/register_library.bash create mode 100644 linux_shell/build_sysroot/3rd_build_syroot/readme.md create mode 100644 linux_shell/build_sysroot/3rd_build_syroot/ubuntu2004/base.bash create mode 100644 linux_shell/build_sysroot/3rd_build_syroot/ubuntu2004/build_sysroot create mode 100644 linux_shell/build_sysroot/3rd_build_syroot/ubuntu2004/init_dev_env create mode 100644 linux_shell/build_sysroot/build_sysroot_from_iso/base_rootfs.bash create mode 100644 linux_shell/build_sysroot/build_sysroot_from_iso/function_rootfs.bash create mode 100644 linux_shell/build_sysroot/build_sysroot_from_iso/test_rootfs.bash diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..f6906f2 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# 已忽略包含查询文件的默认文件夹 +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/install_script/boost/install_boost.bash b/install_script/boost/install_boost.bash new file mode 100644 index 0000000..689db92 --- /dev/null +++ b/install_script/boost/install_boost.bash @@ -0,0 +1,58 @@ +#!/bin/bash +export LANG=en_US.UTF-8 +export LC_ALL=en_US.UTF-8 + +# 检查脚本参数 +if [ "$#" -ne 4 ]; then + echo "Usage: $0 " + exit 1 +fi + + +BOOST_SOURCE_DIR=$1 +BOOST_BUILD_DIR=$2 +BOOST_INSTALL_DIR=$3 +BOOST_BUILD_TYPE=$4 + +BOOST_URL="https://archives.boost.io/release/1.83.0/source/boost_1_83_0.tar.gz" +proxy_URL="http://127.0.0.1:9081" + +export http_proxy="$proxy_URL" +export https_proxy="$proxy_URL" +export ftp_proxy="$proxy_URL" + + +echo "BOOST_SOURCE_DIR $BOOST_SOURCE_DIR" +echo "BOOST_BUILD_DIR $BOOST_BUILD_DIR" +echo "BOOST_INSTALL_DIR $BOOST_INSTALL_DIR" +echo "BOOST_BUILD_TYPE $BOOST_BUILD_TYPE" + +# 如果安装目录不存在 +if [ ! -d "$BOOST_INSTALL_DIR" ]; then + if [ ! -d "$BOOST_BUILD_DIR" ]; then + mkdir -p "$BOOST_BUILD_DIR" + fi + + # 如果源目录不存在,创建它 + mkdir -p "$BOOST_SOURCE_DIR" + cd "$BOOST_SOURCE_DIR" || exit + + # 下载Boost源码包 + if [ ! -f "$BOOST_SOURCE_DIR/boost.tar.gz" ]; then + wget $BOOST_URL -O "$BOOST_SOURCE_DIR/boost.tar.gz" + fi + + # 解压Boost源码包 + if [ ! -d "$BOOST_SOURCE_DIR/boost" ]; then + tar --transform 's/^boost_/boost/' -xzf "$BOOST_SOURCE_DIR/boost.tar.gz" -C "$BOOST_SOURCE_DIR" + fi + + # 执行Bootstrap和构建 + cd "$BOOST_SOURCE_DIR/boost" || exit + ./bootstrap.sh --prefix="$BOOST_INSTALL_DIR" + + + ./b2 variant=$BOOST_BUILD_TYPE link=shared --build-dir="$BOOST_BUILD_DIR" --prefix="$BOOST_INSTALL_DIR" install +else + echo "安装目录已存在,跳过安装!" +fi diff --git a/install_script/boost/install_boost.ps1 b/install_script/boost/install_boost.ps1 new file mode 100644 index 0000000..6c8d3c5 --- /dev/null +++ b/install_script/boost/install_boost.ps1 @@ -0,0 +1,71 @@ +$PSConsoleOutputEncoding +$OutputEncoding = [System.Text.Encoding]::UTF8 +$PSConsoleOutputEncoding = [System.Text.Encoding]::UTF8 + + +#!/usr/bin/env pwsh + +# 设置环境变量 +$env:LANG = "en_US.UTF-8" +$env:LC_ALL = "en_US.UTF-8" + +$BOOST_SOURCE_DIR = $args[0] +$BOOST_BUILD_DIR = $args[1] +$BOOST_INSTALL_DIR = $args[2] +$version=$args[3] +$other_option=$args[4] + +$formattedVersion = $version -replace "\.", "_" +# $version = "1.83.0" +$BOOST_URL = "https://archives.boost.io/release/$version/source/boost_$formattedVersion.tar.gz" +$proxy_URL = "http://127.0.0.1:9081" +$name = "boost_$formattedVersion" + + +# 设置代理 +$env:http_proxy = $proxy_URL +$env:https_proxy = $proxy_URL +$env:ftp_proxy = $proxy_URL + + +echo "BOOST_SOURCE_DIR $BOOST_SOURCE_DIR" +echo "BOOST_BUILD_DIR $BOOST_BUILD_DIR" +echo "BOOST_INSTALL_DIR $BOOST_INSTALL_DIR" +echo "version $version" +echo "other_option $other_option" + + +if (-not (Test-Path $BOOST_INSTALL_DIR)) { + if (-not (Test-Path $BOOST_BUILD_DIR)) { + mkdir -p $BOOST_BUILD_DIR + } + if (-not (Test-Path $BOOST_SOURCE_DIR)) { + mkdir -p $BOOST_SOURCE_DIR + } + Set-Location -Path $BOOST_SOURCE_DIR + + # 下载Boost源码包 + if (-not (Test-Path "$BOOST_SOURCE_DIR\boost.tar.gz")) { + Invoke-WebRequest -Uri $BOOST_URL -OutFile "$BOOST_SOURCE_DIR\boost.tar.gz" + } + + # 解压Boost源码包 + if (-not (Test-Path "$BOOST_SOURCE_DIR\$name")) { + echo "tar..." + tar -xzf "$BOOST_SOURCE_DIR\boost.tar.gz" -C "$BOOST_SOURCE_DIR" + } + Set-Location -Path "$BOOST_SOURCE_DIR\$name" + $bootstrap_cmd = "./bootstrap.bat --prefix=`"$BOOST_INSTALL_DIR`"" + echo "Invoke-Expression bootstrap_cmd: $bootstrap_cmd" + Invoke-Expression $bootstrap_cmd + $b2_cmd = "./b2 $other_option --build-dir=`"$BOOST_BUILD_DIR`" --prefix=`"$BOOST_INSTALL_DIR`" install" + echo "Invoke-Expression b2_cmd: $b2_cmd" + Invoke-Expression $b2_cmd +} else { + echo "intall dir already exisit skip all!" + + exit 0 +} + + +exit 0 diff --git a/install_script/ccache/ccache.ps1 b/install_script/ccache/ccache.ps1 new file mode 100644 index 0000000..53ba86a --- /dev/null +++ b/install_script/ccache/ccache.ps1 @@ -0,0 +1,52 @@ +$ErrorActionPreference = "Stop" +$toolsDir = "D:\ae\tools" +$installDir = "D:\ae\tools\ccache" +$cacheDir = "D:\ae\tools\ccache-cache" +$tmpDir = Join-Path $env:TEMP "ccache_install" +$apiUrl = "https://api.github.com/repos/ccache/ccache/releases/latest" +New-Item -ItemType Directory -Force -Path $toolsDir | Out-Null +New-Item -ItemType Directory -Force -Path $cacheDir | Out-Null +if(Test-Path $tmpDir) { + Remove-Item -Recurse -Force $tmpDir +} +New-Item -ItemType Directory -Force -Path $tmpDir | Out-Null +Write-Host "获取 ccache 最新版本信息..." +$release = Invoke-RestMethod -Uri $apiUrl -Headers @{ "User-Agent" = "PowerShell" } +$asset = $release.assets | Where-Object { $_.name -match "windows-x86_64\.zip$" } | Select-Object -First 1 +if($null -eq $asset) { + throw "没有找到 Windows x86_64 版本的 ccache zip 包" +} +$zipFile = Join-Path $tmpDir $asset.name +Write-Host "下载 $($asset.name)..." +Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $zipFile +Write-Host "解压..." +Expand-Archive -Path $zipFile -DestinationPath $tmpDir -Force +$ccacheExe = Get-ChildItem -Path $tmpDir -Filter "ccache.exe" -Recurse | Select-Object -First 1 +if($null -eq $ccacheExe) { + throw "解压后没有找到 ccache.exe" +} +if(Test-Path $installDir) { + Remove-Item -Recurse -Force $installDir +} +New-Item -ItemType Directory -Force -Path $installDir | Out-Null +Copy-Item -Path (Join-Path $ccacheExe.DirectoryName "*") -Destination $installDir -Recurse -Force +[Environment]::SetEnvironmentVariable("CCACHE_DIR", $cacheDir, "User") +$userPath = [Environment]::GetEnvironmentVariable("Path", "User") +$paths = $userPath -split ";" +if($paths -notcontains $installDir) { + if([string]::IsNullOrWhiteSpace($userPath)) { + $newPath = $installDir + } else { + $newPath = "$userPath;$installDir" + } + [Environment]::SetEnvironmentVariable("Path", $newPath, "User") +} +$env:Path = "$installDir;$env:Path" +$env:CCACHE_DIR = $cacheDir +& "$installDir\ccache.exe" --version +& "$installDir\ccache.exe" -M 20G +& "$installDir\ccache.exe" -s +Remove-Item -Recurse -Force $tmpDir +Write-Host "ccache 已安装到: $installDir" +Write-Host "ccache 缓存目录: $cacheDir" +Write-Host "已经写入用户 PATH,新开的 PowerShell 窗口可直接使用 ccache" \ No newline at end of file diff --git a/install_script/ccache/set_cache_env.ps1 b/install_script/ccache/set_cache_env.ps1 new file mode 100644 index 0000000..7d6544d --- /dev/null +++ b/install_script/ccache/set_cache_env.ps1 @@ -0,0 +1,31 @@ +$ErrorActionPreference = "Stop" +$installDir = "D:\ae\tools\ccache" +$cacheDir = "D:\ae\tools\ccache-cache" +$tmpDir = "D:\ae\tools\ccache-tmp" +New-Item -ItemType Directory -Force -Path $installDir | Out-Null +New-Item -ItemType Directory -Force -Path $cacheDir | Out-Null +New-Item -ItemType Directory -Force -Path $tmpDir | Out-Null +[Environment]::SetEnvironmentVariable("CCACHE_DIR", $cacheDir, "User") +[Environment]::SetEnvironmentVariable("CCACHE_MAXSIZE", "20G", "User") +[Environment]::SetEnvironmentVariable("CCACHE_TEMPDIR", $tmpDir, "User") +$userPath = [Environment]::GetEnvironmentVariable("Path", "User") +$paths = $userPath -split ";" +if($paths -notcontains $installDir) { + if([string]::IsNullOrWhiteSpace($userPath)) { + $newPath = $installDir + } else { + $newPath = "$userPath;$installDir" + } + [Environment]::SetEnvironmentVariable("Path", $newPath, "User") +} +$env:Path = "$installDir;$env:Path" +$env:CCACHE_DIR = $cacheDir +$env:CCACHE_MAXSIZE = "20G" +$env:CCACHE_TEMPDIR = $tmpDir +& "$installDir\ccache.exe" --show-config +& "$installDir\ccache.exe" --show-stats +Write-Host "ccache 环境变量已设置" +Write-Host "ccache 安装目录: $installDir" +Write-Host "ccache 缓存目录: $cacheDir" +Write-Host "ccache 临时目录: $tmpDir" +Write-Host "已经写入用户 PATH,新开的 PowerShell 窗口可直接使用 ccache" \ No newline at end of file diff --git a/install_script/ccache/地址.txt b/install_script/ccache/地址.txt new file mode 100644 index 0000000..d6fbcb1 --- /dev/null +++ b/install_script/ccache/地址.txt @@ -0,0 +1 @@ +https://ccache.dev/download.html \ No newline at end of file diff --git a/install_script/cef/build_cef.ps1 b/install_script/cef/build_cef.ps1 new file mode 100644 index 0000000..3dbd222 --- /dev/null +++ b/install_script/cef/build_cef.ps1 @@ -0,0 +1,231 @@ +chcp.com 65001 > $null + + +function Install-VSNativeDesktopComponents { + param( + [Parameter(Mandatory = $true)] + [string]$InstallerPath, + + [switch]$ARM64 + ) + + if (!(Test-Path $InstallerPath)) { + throw "Installer not found: $InstallerPath" + } + + $args = @( + "--add", "Microsoft.VisualStudio.Workload.NativeDesktop", + "--add", "Microsoft.VisualStudio.Component.VC.ATLMFC", + "--includeRecommended" + ) + + if ($ARM64) { + $args += @( + "--add", "Microsoft.VisualStudio.Component.VC.Tools.ARM64", + "--add", "Microsoft.VisualStudio.Component.VC.MFC.ARM64" + ) + } + + Write-Host "Running installer: $InstallerPath" + Write-Host "Arguments:" + $args | ForEach-Object { Write-Host " $_" } + + & $InstallerPath @args + $exitCode = $LASTEXITCODE + + if ($exitCode -ne 0) { + throw "Visual Studio installer failed with exit code: $exitCode" + } + + Write-Host "Visual Studio components installed successfully." +} + +$script:cache_dir = "D:\wyc\cached_external_library\cef_cache" + +function get_cached_file($url, $cache_path, $out_path) { + $cache_file_path = Join-Path -Path $script:cache_dir -ChildPath $cache_path + + $cache_dir_path = Split-Path -Path $cache_file_path -Parent + if (!(Test-Path $cache_dir_path)) { + New-Item -ItemType Directory -Path $cache_dir_path -Force | Out-Null + } + + if (!(Test-Path $cache_file_path)) { + Write-Host "下载文件: $url" + Invoke-WebRequest -Uri $url -OutFile $cache_file_path + } + else { + Write-Host "缓存已存在,跳过下载: $cache_file_path" + } + + $out_dir = Split-Path -Path $out_path -Parent + if ($out_dir -and !(Test-Path $out_dir)) { + New-Item -ItemType Directory -Path $out_dir -Force | Out-Null + } + + Copy-Item -Path $cache_file_path -Destination $out_path -Force + Write-Host "已复制到: $out_path" +} + +function get_cached_zip($url, $cache_path, $out_path) { + $zip_path = Join-Path -Path $script:cache_dir -ChildPath $cache_path + + $zip_dir = Split-Path -Path $zip_path -Parent + if (!(Test-Path $zip_dir)) { + New-Item -ItemType Directory -Path $zip_dir -Force | Out-Null + } + + if (!(Test-Path $zip_path)) { + Write-Host "下载压缩包: $url" + Invoke-WebRequest -Uri $url -OutFile $zip_path + } + else { + Write-Host "缓存已存在,跳过下载: $zip_path" + } + + if (Test-Path $out_path) { + Remove-Item -Path $out_path -Recurse -Force + } + New-Item -ItemType Directory -Path $out_path -Force | Out-Null + + Write-Host "解压到: $out_path" + Expand-Archive -Path $zip_path -DestinationPath $out_path -Force +} + +function write_text_file { + param( + [string]$file_path, + [string]$content + ) + + $dir = Split-Path -Path $file_path -Parent + if ($dir -and !(Test-Path $dir)) { + New-Item -ItemType Directory -Path $dir -Force | Out-Null + } + + Set-Content -Path $file_path -Value $content -Encoding UTF8 +} + + + +$work_dir +$automate_dir +$depot_tools_dir +$chromium_git_dir +$create_dir +$automate_py +$python3_bat +$depot_tools_url +$automate_url +$ver + +function update_tools(){ + get_cached_zip $depot_tools_url "depot_tools_$ver.zip" $depot_tools_dir + get_cached_file $automate_url "automate_$ver.py" $automate_py + + + & (Join-Path $depot_tools_dir "update_depot_tools.bat") + if ($LASTEXITCODE -ne 0) { + throw "update_depot_tools.bat 执行失败: $LASTEXITCODE" + } + + + + + if (($env:PATH -split ';') -notcontains $depot_tools_dir) { + $env:PATH = "$depot_tools_dir;$env:PATH" + } + + & $python3_bat $automate_py --help + if ($LASTEXITCODE -ne 0) { + throw "automate-git.py --help 执行失败: $LASTEXITCODE" + } + +} + + +function prepare_env($work_dir, $ver, $chromium_ref) { + $script:work_dir="$work_dir" + $script:ver="$ver" + $script:automate_dir = Join-Path $work_dir "automate" + $script:depot_tools_dir = Join-Path $work_dir "depot_tools" + $script:chromium_git_dir = Join-Path $work_dir "chromium_git" + $script:create_dir = Join-Path $work_dir "chromium_git/chromium/src/cef" + $script:automate_py = Join-Path $automate_dir "automate-git.py" + $script:python3_bat = Join-Path $depot_tools_dir "python3.bat" + $script:depot_tools_url = "https://storage.googleapis.com/chrome-infra/depot_tools.zip" + $script:automate_url = "https://raw.githubusercontent.com/chromiumembedded/cef/${ver}/tools/automate/automate-git.py" + + +} + + + + +function generate_update_script(){ + $bat= Join-Path $chromium_git_dir "update.bat" + write_text_file "$bat" @" +@echo off +chcp 65001 >nul +cd /d "$chromium_git_dir" +set "PATH=$depot_tools_dir;%PATH%" +call "$python3_bat" "$automate_py" ^ + --download-dir="$chromium_git_dir" ^ + --depot-tools-dir="$depot_tools_dir" ^ + --no-chromium-history ^ + --no-distrib ^ + --no-build +"@ +} + + +function generate_create_script(){ + $bat = Join-Path $create_dir "create.bat" + echo "bat $bat" + write_text_file "$bat" @" +chcp 65001 >nul +cd ${create_dir} +set "PATH=$depot_tools_dir;%PATH%" +set "GN_DEFINES=is_component_build=true" +set "GN_ARGUMENTS=--ide=vs2022 --sln=cef --filters=//cef/*" +call cef_create_projects.bat +"@ +} + + + +prepare_env "D:\cef_builds\4_4_1436" "7680" "146.0.7680.184" +# prepare_env "D:\cef_builds\4_4_851" "6613" "128.0.6613.138" +update_tools +generate_update_script + + + +& "$chromium_git_dir\update.bat" + +generate_create_script +& "$create_dir\create.bat" + + +$DepotPyDir = "$work_dir\depot_tools\bootstrap-2@3_11_8_chromium_35_bin\python3\bin" +$env:PATH = "$DepotPyDir;$env:PATH" +where.exe python3 +python3 --version + +if (($env:PATH -split ';') -notcontains $depot_tools_dir) { + $env:PATH = "$depot_tools_dir;$env:PATH" +} +Set-Location "$work_dir\chromium_git\chromium\src" + +& "C:\Program Files\JetBrains\CLion 2026.1\bin\ninja\win\x64\ninja.exe" ` + -C "out\Release_GN_x64" ` + cef + + +#Install-VSNativeDesktopComponents -InstallerPath "D:\wyc\Environment\vs_Enterprise2022.exe" + +#D:\cef_builds\4_4_851\chromium_git\chromium\src\out\Release_GN_x64 +& "$work_dir\chromium_git\chromium\src\out\Release_GN_x64\ceftests.exe" + + +exit 0 \ No newline at end of file diff --git a/install_script/cef/build_cef_log.ps1 b/install_script/cef/build_cef_log.ps1 new file mode 100644 index 0000000..01ca6c1 --- /dev/null +++ b/install_script/cef/build_cef_log.ps1 @@ -0,0 +1,636 @@ +chcp.com 65001 > $null + +$script:cache_dir = "D:\wyc\cached_external_library\cef_cache" + + + + +# ============================================ +# 说明 +# 1. 请把本脚本保存为 UTF-8 with BOM +# 2. 不改变现有外部命令的输出方式 +# 3. 额外生成两份日志: +# - transcript:控制台转录,尽量保留原始输出 +# - marker log:北京时间阶段日志 +# ============================================ + +# ========================= +# 北京时间日志 +# ========================= +$script:bj_tz = [System.TimeZoneInfo]::FindSystemTimeZoneById("China Standard Time") +$script:log_dir = $null +$script:marker_log_file = $null +$script:transcript_log_file = $null +$script:transcript_started = $false +$script:build_start_utc = [datetime]::UtcNow + +function Get-BJNow { + return [System.TimeZoneInfo]::ConvertTimeFromUtc([datetime]::UtcNow, $script:bj_tz) +} + +function Get-BJTimeString { + param( + [switch]$ForFileName + ) + + $dt = Get-BJNow + if ($ForFileName) { + return $dt.ToString("yyyyMMdd_HHmmss") + } + return $dt.ToString("yyyy-MM-dd HH:mm:ss.fff") +} + + + +function Invoke-CmdLineLogged { + [CmdletBinding()] + param( + [Parameter(Mandatory, Position = 0)] + [string]$cmdLine + ) + + if ([string]::IsNullOrWhiteSpace($script:NativeCommandLogFile)) { + throw '$script:NativeCommandLogFile 未设置,无法写日志。' + } + + function Write-ConsoleAndLog { + param( + [Parameter(Mandatory)] + [string]$Text + ) + + Write-Host $Text + Add-Content -Path $script:NativeCommandLogFile -Value $Text -Encoding UTF8 + } + + $startTime = Get-Date + $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() + + Write-ConsoleAndLog "================================================================" + Write-ConsoleAndLog ("[开始时间] {0}" -f $startTime.ToString("yyyy-MM-dd HH:mm:ss.fff")) + Write-ConsoleAndLog ("[执行命令] {0}" -f $cmdLine) + Write-ConsoleAndLog "----------------------------------------------------------------" + + cmd.exe /d /c $cmdLine 2>&1 | + Tee-Object -FilePath $script:NativeCommandLogFile -Append | + Out-Host + + $exitCode = $LASTEXITCODE + $script:LastNativeExitCode = $exitCode + + $stopwatch.Stop() + $endTime = Get-Date + $elapsed = $stopwatch.Elapsed + + Write-ConsoleAndLog "----------------------------------------------------------------" + Write-ConsoleAndLog ("[结束时间] {0}" -f $endTime.ToString("yyyy-MM-dd HH:mm:ss.fff")) + Write-ConsoleAndLog ("[耗时] {0:hh\:mm\:ss\.fff}" -f $elapsed) + Write-ConsoleAndLog ("[退出码] {0}" -f $exitCode) + Write-ConsoleAndLog "================================================================" + + return $exitCode +} + +#function Write-MarkerLog { +# param( +# [Parameter(Mandatory = $true)] +# [string]$Message, +# +# [ValidateSet("INFO", "STEP", "WARN", "ERROR")] +# [string]$Level = "INFO" +# ) +# +# if ([string]::IsNullOrWhiteSpace($script:marker_log_file)) { +# return +# } +# +# $line = "[{0}] [{1}] {2}" -f (Get-BJTimeString), $Level, $Message +# Add-Content -Path $script:marker_log_file -Value $line -Encoding UTF8 +#} +function Write-MarkerLog { + param( + [Parameter(Mandatory = $true)] + [string]$Message, + + [ValidateSet("INFO", "STEP", "WARN", "ERROR")] + [string]$Level = "INFO" + ) + + $line = "[{0}] [{1}] {2}" -f (Get-BJTimeString), $Level, $Message + Write-Host $line +} +function Initialize-Logging { + param( + [Parameter(Mandatory = $true)] + [string]$BaseDir + ) + + $script:log_dir = Join-Path $BaseDir "logs" + if (!(Test-Path $script:log_dir)) { + New-Item -ItemType Directory -Path $script:log_dir -Force | Out-Null + } + + $ts = Get-BJTimeString -ForFileName + $script:marker_log_file = Join-Path $script:log_dir ("cef_build_{0}.bj.log" -f $ts) + $script:transcript_log_file = Join-Path $script:log_dir ("cef_build_{0}.transcript.log" -f $ts) + + New-Item -ItemType File -Path $script:marker_log_file -Force | Out-Null + + Start-Transcript -Path $script:transcript_log_file -Force | Out-Null + $script:transcript_started = $true + + Write-MarkerLog "日志初始化完成" + Write-MarkerLog "marker_log=$script:marker_log_file" + Write-MarkerLog "transcript_log=$script:transcript_log_file" +} + +#function Invoke-Step { +# param( +# [Parameter(Mandatory = $true)] +# [string]$Name, +# +# [Parameter(Mandatory = $true)] +# [scriptblock]$Action +# ) +# +# Write-MarkerLog "$Name 开始" "STEP" +# $sw = [System.Diagnostics.Stopwatch]::StartNew() +# +# & $Action +# +# $sw.Stop() +# Write-MarkerLog ("{0} 完成,耗时={1:n2}s" -f $Name, $sw.Elapsed.TotalSeconds) "STEP" +#} + + +function Invoke-Step { + param( + [Parameter(Mandatory = $true)] + [string]$Name, + + [Parameter(Mandatory = $true)] + [scriptblock]$Action + ) + + Write-MarkerLog "$Name 开始" "STEP" + $sw = [System.Diagnostics.Stopwatch]::StartNew() + + $oldVerbosePreference = $VerbosePreference + $oldDebugPreference = $DebugPreference + $oldInformationPreference = $InformationPreference + + try { + $VerbosePreference = 'Continue' + $DebugPreference = 'Continue' + $InformationPreference = 'Continue' + + if ([string]::IsNullOrWhiteSpace($script:marker_log_file)) { + & $Action *>&1 | Out-Host + } + else { + & $Action *>&1 | + Tee-Object -FilePath $script:marker_log_file -Append | + Out-Host + } + + if ($LASTEXITCODE -ne 0) { + throw "步骤 '$Name' 执行失败,退出码=$LASTEXITCODE" + } + } + catch { + Write-MarkerLog ("{0} 失败: {1}" -f $Name, $_.Exception.Message) "ERROR" + throw + } + finally { + $VerbosePreference = $oldVerbosePreference + $DebugPreference = $oldDebugPreference + $InformationPreference = $oldInformationPreference + + $sw.Stop() + Write-MarkerLog ("{0} 完成,耗时={1:n2}s" -f $Name, $sw.Elapsed.TotalSeconds) "STEP" + } +} + + +function Install-VSNativeDesktopComponents { + param( + [Parameter(Mandatory = $true)] + [string]$InstallerPath, + + [switch]$ARM64 + ) + + if (!(Test-Path $InstallerPath)) { + throw "Installer not found: $InstallerPath" + } + + $args = @( + "--add", "Microsoft.VisualStudio.Workload.NativeDesktop", + "--add", "Microsoft.VisualStudio.Component.VC.ATLMFC", + "--includeRecommended" + ) + + if ($ARM64) { + $args += @( + "--add", "Microsoft.VisualStudio.Component.VC.Tools.ARM64", + "--add", "Microsoft.VisualStudio.Component.VC.MFC.ARM64" + ) + } + + Write-MarkerLog "Install-VSNativeDesktopComponents 开始: $InstallerPath" "STEP" + Write-Host "Running installer: $InstallerPath" + Write-Host "Arguments:" + $args | ForEach-Object { Write-Host " $_" } + + & $InstallerPath @args + $exitCode = $LASTEXITCODE + Write-MarkerLog "VS 安装器退出码: $exitCode" + + if ($exitCode -ne 0) { + throw "Visual Studio installer failed with exit code: $exitCode" + } + + Write-Host "Visual Studio components installed successfully." + Write-MarkerLog "Install-VSNativeDesktopComponents 完成" "STEP" +} + + + +function get_cached_file($url, $cache_path, $out_path) { + $cache_file_path = Join-Path -Path $script:cache_dir -ChildPath $cache_path + + $cache_dir_path = Split-Path -Path $cache_file_path -Parent + if (!(Test-Path $cache_dir_path)) { + New-Item -ItemType Directory -Path $cache_dir_path -Force | Out-Null + } + + Write-MarkerLog "get_cached_file: url=$url" + Write-MarkerLog "get_cached_file: cache=$cache_file_path" + Write-MarkerLog "get_cached_file: out=$out_path" + + if (!(Test-Path $cache_file_path)) { + Write-Host "下载文件: $url" + Invoke-WebRequest -Uri $url -OutFile $cache_file_path + Write-MarkerLog "文件下载完成: $cache_file_path" + } + else { + Write-Host "缓存已存在,跳过下载: $cache_file_path" + Write-MarkerLog "命中缓存: $cache_file_path" + } + + $out_dir = Split-Path -Path $out_path -Parent + if ($out_dir -and !(Test-Path $out_dir)) { + New-Item -ItemType Directory -Path $out_dir -Force | Out-Null + } + + Copy-Item -Path $cache_file_path -Destination $out_path -Force + Write-Host "已复制到: $out_path" + Write-MarkerLog "复制完成: $out_path" +} + +function get_cached_zip($url, $cache_path, $out_path) { + $zip_path = Join-Path -Path $script:cache_dir -ChildPath $cache_path + + $zip_dir = Split-Path -Path $zip_path -Parent + if (!(Test-Path $zip_dir)) { + New-Item -ItemType Directory -Path $zip_dir -Force | Out-Null + } + + Write-MarkerLog "get_cached_zip: url=$url" + Write-MarkerLog "get_cached_zip: cache=$zip_path" + Write-MarkerLog "get_cached_zip: out=$out_path" + + if (!(Test-Path $zip_path)) { + Write-Host "下载压缩包: $url" + Invoke-WebRequest -Uri $url -OutFile $zip_path + Write-MarkerLog "压缩包下载完成: $zip_path" + } + else { + Write-Host "缓存已存在,跳过下载: $zip_path" + Write-MarkerLog "命中缓存: $zip_path" + } + + if (Test-Path $out_path) { + Remove-Item -Path $out_path -Recurse -Force + Write-MarkerLog "删除旧目录: $out_path" + } + New-Item -ItemType Directory -Path $out_path -Force | Out-Null + + Write-Host "解压到: $out_path" + Expand-Archive -Path $zip_path -DestinationPath $out_path -Force + Write-MarkerLog "解压完成: $out_path" +} + +function write_text_file { + param( + [string]$file_path, + [string]$content + ) + + $dir = Split-Path -Path $file_path -Parent + if ($dir -and !(Test-Path $dir)) { + New-Item -ItemType Directory -Path $dir -Force | Out-Null + } + + Set-Content -Path $file_path -Value $content -Encoding UTF8 + Write-MarkerLog "写入文件: $file_path" +} + +$work_dir = $null +$automate_dir = $null +$depot_tools_dir = $null +$chromium_git_dir = $null +$create_dir = $null +$automate_py = $null +$python3_bat = $null +$depot_tools_url = $null +$automate_url = $null +$ver = $null +$script:chromium_ref = $null + +function update_tools() { + Invoke-Step "update_tools" { + get_cached_zip $depot_tools_url "depot_tools_$ver.zip" $depot_tools_dir + get_cached_file $automate_url "automate_$ver.py" $automate_py + + Write-MarkerLog "执行: $(Join-Path $depot_tools_dir 'update_depot_tools.bat')" + & (Join-Path $depot_tools_dir "update_depot_tools.bat") + Write-MarkerLog "update_depot_tools.bat 退出码: $LASTEXITCODE" + if ($LASTEXITCODE -ne 0) { + throw "update_depot_tools.bat 执行失败: $LASTEXITCODE" + } + + if (($env:PATH -split ';') -notcontains $depot_tools_dir) { + $env:PATH = "$depot_tools_dir;$env:PATH" + Write-MarkerLog "已追加 depot_tools 到 PATH" + } + + Write-MarkerLog "执行: $python3_bat $automate_py --help" + & $python3_bat $automate_py --help + Write-MarkerLog "automate-git.py --help 退出码: $LASTEXITCODE" + if ($LASTEXITCODE -ne 0) { + throw "automate-git.py --help 执行失败: $LASTEXITCODE" + } + } +} + +function prepare_env($work_dir, $ver, $chromium_ref) { + $script:work_dir="$work_dir" + $script:ver="$ver" + $script:chromium_ref = "$chromium_ref" + $script:automate_dir = Join-Path $work_dir "automate" + $script:depot_tools_dir = Join-Path $work_dir "depot_tools" + $script:chromium_git_dir = Join-Path $work_dir "chromium_git" + $script:create_dir = Join-Path $work_dir "chromium_git/chromium/src/cef" + $script:automate_py = Join-Path $automate_dir "automate-git.py" + $script:python3_bat = Join-Path $depot_tools_dir "python3.bat" + $script:depot_tools_url = "https://storage.googleapis.com/chrome-infra/depot_tools.zip" + $script:automate_url = "https://raw.githubusercontent.com/chromiumembedded/cef/${ver}/tools/automate/automate-git.py" +} + +function generate_update_script(){ + $bat= Join-Path $chromium_git_dir "update.bat" + write_text_file "$bat" @" +@echo off +chcp 65001 >nul +cd /d "$chromium_git_dir" +set "PATH=$depot_tools_dir;%PATH%" +call "$python3_bat" "$automate_py" ^ + --download-dir="$chromium_git_dir" ^ + --depot-tools-dir="$depot_tools_dir" ^ + --no-chromium-history ^ + --no-distrib ^ + --no-build +"@ + Write-MarkerLog "已生成 update.bat: $bat" +} + +function generate_create_script(){ + $bat = Join-Path $create_dir "create.bat" + echo "bat $bat" + write_text_file "$bat" @" +chcp 65001 >nul +cd ${create_dir} +set "PATH=$depot_tools_dir;%PATH%" +set "GN_DEFINES=is_component_build=true" +set "GN_ARGUMENTS=--ide=vs2022 --sln=cef --filters=//cef/*" +call cef_create_projects.bat +"@ + Write-MarkerLog "已生成 create.bat: $bat" +} + +if ($true) { + try { + + #prepare_env "D:\cef_builds\4_4_1436" "7680" "146.0.7680.184" + #prepare_env "D:\cef_builds\4_4_1913" "6613" "128.0.6613.138" 这个构建不了 不带--no-chromium-history 源码下载不下来 + # prepare_env "D:\cef_builds\4_7_1048" "7204" "138.0.7204.50" 这个构建不了 不带--no-chromium-history 源码下载不下来 + prepare_env "D:\cef_builds\4_7_1129" "7680" "146.0.7680.184" + + + Initialize-Logging -BaseDir $work_dir + Write-MarkerLog "构建开始" "STEP" + Write-MarkerLog "work_dir=$work_dir" + Write-MarkerLog "CEF branch=$ver" + Write-MarkerLog "chromium_ref=$script:chromium_ref" + + update_tools + + Invoke-Step "generate_update_script" { + generate_update_script + } + + Invoke-Step "执行 update.bat" { + Write-MarkerLog "执行: $chromium_git_dir\update.bat" + & "$chromium_git_dir\update.bat" + Write-MarkerLog "update.bat 退出码: $LASTEXITCODE" + if ($LASTEXITCODE -ne 0) { + throw "update.bat 执行失败: $LASTEXITCODE" + } + } + + Invoke-Step "generate_create_script" { + generate_create_script + } + + Invoke-Step "执行 create.bat" { + Write-MarkerLog "执行: $create_dir\create.bat" + & "$create_dir\create.bat" + Write-MarkerLog "create.bat 退出码: $LASTEXITCODE" + if ($LASTEXITCODE -ne 0) { + throw "create.bat 执行失败: $LASTEXITCODE" + } + } + + $DepotPyDir = "$work_dir\depot_tools\bootstrap-2@3_11_8_chromium_35_bin\python3\bin" + $env:PATH = "$DepotPyDir;$env:PATH" + Write-MarkerLog "已追加 DepotPyDir 到 PATH: $DepotPyDir" + + Invoke-Step "where.exe python3" { + where.exe python3 + Write-MarkerLog "where.exe 退出码: $LASTEXITCODE" + if ($LASTEXITCODE -ne 0) { + throw "where.exe python3 执行失败: $LASTEXITCODE" + } + } + + Invoke-Step "python3 --version" { + python3 --version + Write-MarkerLog "python3 --version 退出码: $LASTEXITCODE" + if ($LASTEXITCODE -ne 0) { + throw "python3 --version 执行失败: $LASTEXITCODE" + } + } + + if (($env:PATH -split ';') -notcontains $depot_tools_dir) { + $env:PATH = "$depot_tools_dir;$env:PATH" + Write-MarkerLog "再次确保 depot_tools 在 PATH 中" + } + + Set-Location "$work_dir\chromium_git\chromium\src" + Write-MarkerLog "切换目录到: $(Get-Location)" + + Invoke-Step "ninja cef" { + & "C:\Program Files\JetBrains\CLion 2026.1\bin\ninja\win\x64\ninja.exe" ` + -C "out\Release_GN_x64" ` + cef + + Write-MarkerLog "ninja 退出码: $LASTEXITCODE" + if ($LASTEXITCODE -ne 0) { + throw "ninja cef 执行失败: $LASTEXITCODE" + } + } + + #Install-VSNativeDesktopComponents -InstallerPath "D:\wyc\Environment\vs_Enterprise2022.exe" + + #D:\cef_builds\4_4_851\chromium_git\chromium\src\out\Release_GN_x64 + Invoke-Step "运行 ceftests.exe" { + $exe = Join-Path $work_dir 'chromium_git\chromium\src\out\Release_GN_x64\ceftests.exe' + $xmlFile = Join-Path $work_dir 'ceftests.xml' + $script:NativeCommandLogFile = Join-Path $work_dir 'ceftests.log' + + #$cmdLine = "`"$exe`" --gtest_color=yes --proxy-server=`"http://127.0.0.1:7897`" --proxy-bypass-list=`"localhost;127.0.0.1`" --gtest_output=xml:`"$xmlFile`" 2>&1" + $cmdLine = "`"$exe`" --gtest_color=yes --no-proxy-server --disable-background-networking --gtest_filter=`"OSRTest.*:ViewsButtonTest.*:ViewsTextfieldTest.*:ViewsWindowTest.WindowAccelerator`" --gtest_output=xml:`"$xmlFile`" 2>&1" + $exitCode = Invoke-CmdLineLogged $cmdLine + + Write-MarkerLog "ceftests.exe 退出码: $exitCode" + Write-MarkerLog "日志文件: $script:NativeCommandLogFile" + Write-MarkerLog "XML报告: $xmlFile" + + if ($exitCode -ne 0) { + throw "ceftests.exe 执行失败: $exitCode,详见: $script:NativeCommandLogFile" + } + } + + Invoke-Step "安装动态库" { + $toolsDir = Join-Path $work_dir 'chromium_git\chromium\src\cef\tools' + $outputDir = Join-Path $work_dir 'distrib' + + Push-Location $toolsDir + try { + $args = @( + 'make_distrib.py' + '--output-dir', $outputDir + '--ninja-build' + '--x64-build' + '--minimal' + '--allow-partial' + '--no-symbols' + '--no-docs' + '--no-archive' + ) + + & python @args + + $exitCode = $LASTEXITCODE + Write-MarkerLog "make_distrib.py 退出码: $exitCode" + Write-MarkerLog "输出目录: $outputDir" + + if ($exitCode -ne 0) { + throw "make_distrib.py 执行失败: $exitCode" + } + } + finally { + Pop-Location + } + } + + + Write-MarkerLog "全部流程执行完成" "STEP" + exit 0 + } + catch { + Write-MarkerLog ("执行失败: " + $_.Exception.Message) "ERROR" + throw + } + finally { + $elapsed = [datetime]::UtcNow - $script:build_start_utc + Write-MarkerLog ("总耗时: {0:n2} 分钟" -f $elapsed.TotalMinutes) + + if ($script:transcript_started) { + try { + Stop-Transcript | Out-Null + } + catch { + } + } + } +} else { + + prepare_env "D:\cef_builds\4_4_1436" "7680" "146.0.7680.184" + + + #Invoke-Step "运行 ceftests.exe" { + # $exe = Join-Path $work_dir 'chromium_git\chromium\src\out\Release_GN_x64\ceftests.exe' + # $xmlFile = Join-Path $work_dir 'ceftests.xml' + # $script:NativeCommandLogFile = Join-Path $work_dir 'ceftests.log' + # + # #$cmdLine = "`"$exe`" --gtest_color=yes --proxy-server=`"http://127.0.0.1:7897`" --proxy-bypass-list=`"localhost;127.0.0.1`" --gtest_output=xml:`"$xmlFile`" 2>&1" + # $cmdLine = "`"$exe`" --gtest_color=yes --no-proxy-server --disable-background-networking --gtest_filter=`"OSRTest.*:ViewsButtonTest.*:ViewsTextfieldTest.*:ViewsWindowTest.WindowAccelerator`" --gtest_output=xml:`"$xmlFile`" 2>&1" + # $exitCode = Invoke-CmdLineLogged $cmdLine + # + # Write-MarkerLog "ceftests.exe 退出码: $exitCode" + # Write-MarkerLog "日志文件: $script:NativeCommandLogFile" + # Write-MarkerLog "XML报告: $xmlFile" + # + # if ($exitCode -ne 0) { + # throw "ceftests.exe 执行失败: $exitCode,详见: $script:NativeCommandLogFile" + # } + #} + + Invoke-Step "安装动态库" { + $toolsDir = Join-Path $work_dir 'chromium_git\chromium\src\cef\tools' + $outputDir = Join-Path $work_dir 'distrib' + + Push-Location $toolsDir + try { + $args = @( + 'make_distrib.py' + '--output-dir', $outputDir + '--ninja-build' + '--x64-build' + '--minimal' + '--allow-partial' + '--no-symbols' + '--no-docs' + '--no-archive' + ) + + & python @args + + $exitCode = $LASTEXITCODE + Write-MarkerLog "make_distrib.py 退出码: $exitCode" + Write-MarkerLog "输出目录: $outputDir" + + if ($exitCode -ne 0) { + throw "make_distrib.py 执行失败: $exitCode" + } + } + finally { + Pop-Location + } + } +} + + + diff --git a/install_script/cef/git_trace.log b/install_script/cef/git_trace.log new file mode 100644 index 0000000000000000000000000000000000000000..dc18bb1528faf9b226b46433680972b4171ded12 GIT binary patch literal 13722 zcmeI3ZBrZB5ryyPRPBG5a;nzYyFvnEY)IH$B4gHx-?HHHhust_gTV3%L4@!cr)u|~ zCpk~IE;B--kr3!5RVfu{G;=l6-S>3&>AqM0`S($1gic7py8f2*S`QDyn*Oiocu{|q z@K~=U{UzbOMs~uf&hKl)U&2XS|ckQ`{dVWiv zx%){tvvd18ZtK%=_#*s4*Uxpd7>;!2ME{$iu5sL_Ejj8Y4Pz6#Q=&V(*V#npTYB%< zs6-Mp?3;hmm2-Wcryl9}Kw}O=&7|t+JWu@Y-NM@!uUfw+;fbXFNg5-~2RmwNY)g0D z)7Wzz?Ma53KL2F09O}KJJEF&)N!XMer}~U#SM|KNKYsZyw>3}tN@wB>lyrxzjs2;g z!iB6DEx#VhdM$bBhAH{{wLvQ(}6qxcIz)>j&scus-}D0=B6!4<6Orv z*>|*lDLZz;jx17_whfz=y5@ju3(~6ye~Z#~QR9kcFEQQysq1%KEXoQb? z3V1)(3(OqoS#h-6k^lKRuW2@yeU=vo3lAB-Qj@*v5U!vjfHF`PwA z-YgolWErr4*I>bpES4vs<0F+D3BmtTU}jHk4v1sX52mHTD`EPjX0|FDBRw$zjhcpq z?{#)Jyf&Xj*2Jz6$vTF!M%RB1>{A{VZr9?Vx2dOl%pywe>r*-hNq8p>4)v-FG1IZ( zmPN~&o{VRmDb^(++KrjTzlegp)^(&HAv(l-F>03{#~a}r$+RO2 z#=KV7ER$#27JVwhZTjMF;NqP$^vnU$E7I7%ze%6E{JvyzZ(39!mrmc# zgP#aHCVuqi=V8&|&&G*iAp2qne7`6{3@bg`)yrA!ZTxut*#c1(ZQ0Fm8pdLJ^cFC+zijf0bh1=4SA%g`<`6# zth3Bhq8Cj^vRz5Gqc}t!CYmiM)4vg8y=P3tuVMkOU*Kl7@Qdt;U6HVA(b@Bl$1>-a z&ercq<9t1cR%=$T65VcINf2u`t(pXt&RM9HJ>MM3;x+3KJXIF-{y{lx>$syaNO)}7 z@kqIGRdKzndvp|^%fiZ;#+P+WwxvJ7aZR}io(#X^Zd5>Aou;m*l7dbLy0$FN=4D8D zz_RseusAXK=CMfoE2 z{z=YFo^FHl9(iQ8v$LbT{oE|x&#`-Zq*vp$XFPg>w-gm_8 zH^mAbDu) z?KDEi$TXN^O+rFCL21T|Orkf&PAeuQ%1zAE2b(kR8B~?MH^O}}h3pCoeL;FwaGSUi zGx^y>K3F_#inSRyj`O(}c9zaCt0=5Wts6FdrHYyp_C;03^=%<|cS;DP_V^@}H6%4L zFe~+6jV01;WBsgGYS%fC-Qvz~;f63<}#=aRK;%(^Pic%w+js^KdgZ_5|r8l+$n`8nMe7v>IgNO~Y##U*jq)mvT(KYGXRlu1?MKS% zj@0ZrBV!LVqf~x$QmMR3-3;kZoEAbyvmfiIiK^c;C(p0_oMFtD{g$t3KS$GPmo2rs z=yT0L-!fl~%n%2vDL~qykQ$em>6JuO4#u)imTrnQjD=%7?qOwR=(KvE$ zI!f=B_07EAZOkcyB_7r*FOnFK+*Z7zGNp@@&8WvZbEX(Z&xzOqm+*f0o?@Hxp$lC* z)Ol7%I*NkCKO~N8K2#*^vnkt{L*4IN!x`MuGtx$PY)Nr}{_TnG41ebd`^p0Sz5Kym zIXN5Md}VGHQcq?@Zt{rS)Xc+HsFFbFec|W+Sl)b7-^fZ*lAq9FqXzN)JILmHwb+5> zy;ko-ABE2vb80>5cfvlA;j@t6>3UE;tC<{r={eWrX)s@;raQ~tE_@6YJPUMsue;Rk zhqK29+xi|AXM?e4xuKXceF?{T;`P^ISatoUv3uw2UfHHAS?uwm0*&h#zCx2P8@r%Z zmDQGPefDZ*yS{8!yEF^hQ8rpv{iV%U-PZM~I^s-HpAh%q%v2}~%EE)Ypa0hfOd2kaw)p3E$l?3{#2I z@$mZmYa3tE=e2>~>ixz%_yPHGl<32_Sd4Lv+vYTR|&5E zs=y^o6#4jt4Ga|S!|D#Z{kh8TZusnV2>WS#{}z2+zdK{Sm(FUzU5lms0_jZHKOT*Lk7qf`p@WUhbM#>`FQ$r$dug8Qx2Nqa6v)yVuya)|Re*g&1 | Tee-Object git_trace.log \ No newline at end of file diff --git a/install_script/cef/选项说明.txt b/install_script/cef/选项说明.txt new file mode 100644 index 0000000..cda5ab1 --- /dev/null +++ b/install_script/cef/选项说明.txt @@ -0,0 +1,124 @@ +PS C:\Users\wyc> D:\cef_builds\cef_7680\depot_tools\python3 D:\cef_builds\cef_7680\automate\automate-git.py --help +Usage: automate-git.py [options] + + This utility implements automation for the download, update, build and +distribution of CEF. + +Options: + -h, --help show this help message and exit + --download-dir=DIR Download directory with no spaces [required]. + --depot-tools-dir=DIR + Download directory for depot_tools. + --depot-tools-archive=DEPOTTOOLSARCHIVE + Archive file that contains a single top-level + depot_tools directory. + --depot-tools-archive-sha256=DEPOTTOOLSARCHIVESHA256 + SHA256 hex-encoded hash for the file passed to + --depot-tools-archive. + --branch=BRANCH Branch of CEF to build (master, 3987, ...). This will + be used to name the CEF download directory and to + identify the correct URL if --url is not specified. + The default value is master. + --url=URL CEF download URL. If not specified the default URL + will be used. + --chromium-url=CHROMIUMURL + Chromium download URL. If not specified the default + URL will be used. + --checkout=CHECKOUT Version of CEF to checkout. If not specified the most + recent remote version of the branch will be used. + --chromium-checkout=CHROMIUMCHECKOUT + Version of Chromium to checkout (Git branch/hash/tag). + This overrides the value specified by CEF in + CHROMIUM_BUILD_COMPATIBILITY.txt. + --no-chromium-history + Checkout Chromium without history. + --chromium-archive=CHROMIUMARCHIVE + Archive file that contains a single top-level chromium + src directory. + --chromium-archive-sha256=CHROMIUMARCHIVESHA256 + SHA256 hex-encoded hash for the file passed to + --chromium-archive. + --force-config Force creation of a new gclient config file. + --force-clean Force a clean checkout of Chromium and CEF. This will + trigger a new update, build and distribution. + --force-clean-deps Force a clean checkout of Chromium dependencies. Used + in combination with --force-clean. + --dry-run Output commands without executing them. + --dry-run-platform=DRYRUNPLATFORM + Simulate a dry run on the specified platform (windows, + mac, linux). Must be used in combination with the + --dry-run flag. + --force-update Force a Chromium and CEF update. This will trigger a + new build and distribution. + --no-update Do not update Chromium or CEF. Pass --force-build or + --force-distrib if you desire a new build or + distribution. + --no-cef-update Do not update CEF. Pass --force-build or --force- + distrib if you desire a new build or distribution. + --force-cef-update Force a CEF update. This will cause local changes in + the CEF checkout to be discarded and patch files to be + reapplied. + --no-chromium-update Do not update Chromium. + --no-depot-tools-update + Do not update depot_tools. + --fast-update Update existing Chromium/CEF checkouts for fast + incremental builds by attempting to minimize the + number of modified files. The update will fail if + there are unstaged CEF changes or if Chromium changes + are not included in a patch file. + --force-patch-update Force update of patch files. + --resave Resave patch files. + --log-chromium-changes + Create a log of the Chromium changes. + --force-build Force CEF debug and release builds. This builds + [build-target] on all platforms and chrome_sandbox on + Linux. + --no-build Do not build CEF. + --build-target=BUILDTARGET + Target name(s) to build (defaults to "cefclient"). + --build-tests Also build the test target specified via --test- + target. + --no-debug-build Don't perform the CEF debug build. + --no-release-build Don't perform the CEF release build. + --verbose-build Show all command lines while building. + --build-failure-limit=BUILDFAILURELIMIT + Keep going until N jobs fail. + --build-log-file Write build logs to file. The file will be named + "build-[branch]-[debug|release].log" in the download + directory. + --x64-build Create a 64-bit build. + --arm-build Create an ARM build. + --arm64-build Create an ARM64 build. + --with-pgo-profiles Download PGO profiles for the build. + --run-tests Run the ceftests target. + --no-debug-tests Don't run debug build tests. + --no-release-tests Don't run release build tests. + --test-target=TESTTARGET + Test target name to build (defaults to "ceftests"). + --test-prefix=TESTPREFIX + Prefix for running the test executable (e.g. `xvfb- + run` on Linux). + --test-args=TESTARGS Arguments that will be passed to the test executable. + --force-distrib Force creation of a CEF binary distribution. + --no-distrib Don't create a CEF binary distribution. + --minimal-distrib Create a minimal CEF binary distribution. + --minimal-distrib-only + Create a minimal CEF binary distribution only. + --client-distrib Create a client CEF binary distribution. + --client-distrib-only + Create a client CEF binary distribution only. + --sandbox-distrib Create a sandbox distribution. + --sandbox-distrib-only + Create a sandbox distribution only. + --tools-distrib Create a tools distribution. + --tools-distrib-only Create a tools distribution only. + --no-distrib-symbols Don't create CEF symbol output directories. + --no-distrib-docs Don't create CEF documentation. + --no-distrib-archive Don't create archives for output directories. + --clean-artifacts Clean the artifacts output directory. + --distrib-subdir=DISTRIBSUBDIR + CEF distrib dir name, child of + chromium/src/cef/binary_distrib + --distrib-subdir-suffix=DISTRIBSUBDIRSUFFIX + CEF distrib dir name suffix, child of + chromium/src/cef/binary_distrib \ No newline at end of file diff --git a/install_script/msys2/install.ps1 b/install_script/msys2/install.ps1 new file mode 100644 index 0000000..150a643 --- /dev/null +++ b/install_script/msys2/install.ps1 @@ -0,0 +1,162 @@ +$ErrorActionPreference = "Stop" + +$MsysRootWin = "C:/msys64" +$MsysRootNative = "C:\msys64" +$MsysRootUnix = "/c/msys64" +$Msys2DistUrl = "https://repo.msys2.org/distrib/x86_64/" +$DownloadDir = Join-Path $env:TEMP "msys2-installer" + +New-Item -ItemType Directory -Force -Path $DownloadDir | Out-Null + +Write-Host "==> Finding latest MSYS2 installer..." + +$page = Invoke-WebRequest -Uri $Msys2DistUrl -UseBasicParsing +$installerName = [regex]::Matches($page.Content, "msys2-x86_64-[0-9]{8}\.exe") | + ForEach-Object { $_.Value } | + Sort-Object -Unique | + Select-Object -Last 1 + +if (-not $installerName) { + throw "Could not find latest MSYS2 installer." +} + +$installerUrl = "$Msys2DistUrl$installerName" +$installerPath = Join-Path $DownloadDir $installerName + +Write-Host "==> Latest installer: $installerName" +Write-Host "==> URL: $installerUrl" + +if (-not (Test-Path $installerPath)) { + Write-Host "==> Downloading installer..." + Invoke-WebRequest -Uri $installerUrl -OutFile $installerPath +} else { + Write-Host "==> Installer already exists: $installerPath" +} + +Write-Host "==> Installing MSYS2 to $MsysRootWin..." + +if (Test-Path "$MsysRootNative\usr\bin\bash.exe") { + Write-Host "==> MSYS2 already exists, skipping installer." +} else { + $env:MSYS2_ARG_CONV_EXCL = "*" + + $args = @( + "in", + "--confirm-command", + "--accept-messages", + "--root", + $MsysRootWin + ) + + $p = Start-Process -FilePath $installerPath -ArgumentList $args -Wait -PassThru + + if ($p.ExitCode -ne 0) { + throw "MSYS2 installer failed. Exit code: $($p.ExitCode)" + } +} + +$MsysBash = "$MsysRootNative\usr\bin\bash.exe" + +if (-not (Test-Path $MsysBash)) { + throw "MSYS2 bash not found: $MsysBash" +} + +function Invoke-Msys { + param( + [Parameter(Mandatory = $true)] + [string] $Command, + + [switch] $IgnoreExitCode + ) + + Write-Host "" + Write-Host "==> MSYS2: $Command" + + & $MsysBash -lc $Command + $code = $LASTEXITCODE + + if ($code -ne 0) { + Write-Host "MSYS2 command exit code: $code" + + if (-not $IgnoreExitCode) { + throw "MSYS2 command failed: $Command" + } + } +} + +Write-Host "==> Initializing MSYS2..." +Invoke-Msys "exit" + +Write-Host "==> Updating MSYS2 core system..." +Write-Host "==> First pacman -Syuu may terminate inner bash. This is expected." + +Invoke-Msys "pacman -Syuu --noconfirm" -IgnoreExitCode +Start-Sleep -Seconds 5 + +Invoke-Msys "pacman -Syuu --noconfirm" -IgnoreExitCode +Start-Sleep -Seconds 3 + +Invoke-Msys "pacman -Syuu --noconfirm" -IgnoreExitCode +Start-Sleep -Seconds 3 + +Write-Host "==> Installing UCRT64 MinGW toolchain and packages..." + +$packages = @( + "git", + "make", + "patch", + "diffutils", + "mingw-w64-ucrt-x86_64-gcc", + "mingw-w64-ucrt-x86_64-cmake", + "mingw-w64-ucrt-x86_64-ninja", + "mingw-w64-ucrt-x86_64-openssl", + "mingw-w64-ucrt-x86_64-pkgconf", + "mingw-w64-ucrt-x86_64-gdb", + "mingw-w64-ucrt-x86_64-make" +) + +$packageLine = $packages -join " " + +Invoke-Msys "pacman -S --needed --noconfirm $packageLine" + +Write-Host "==> Checking installed tools..." + +Invoke-Msys @" +export PATH=/ucrt64/bin:`$PATH +echo gcc: +gcc --version | head -n 1 +echo g++: +g++ --version | head -n 1 +echo cmake: +cmake --version | head -n 1 +echo ninja: +ninja --version +echo gdb: +gdb --version | head -n 1 +echo openssl: +openssl version +echo pkg-config openssl: +pkg-config --modversion openssl +"@ + +Write-Host "" +Write-Host "============================================================" +Write-Host "Done." +Write-Host "" +Write-Host "CLion toolchain paths:" +Write-Host "C compiler: C:\msys64\ucrt64\bin\gcc.exe" +Write-Host "C++ compiler: C:\msys64\ucrt64\bin\g++.exe" +Write-Host "Debugger: C:\msys64\ucrt64\bin\gdb.exe" +Write-Host "CMake: C:\msys64\ucrt64\bin\cmake.exe" +Write-Host "Ninja: C:\msys64\ucrt64\bin\ninja.exe" +Write-Host "" +Write-Host "CMake OpenSSL option:" +Write-Host "-DOPENSSL_ROOT_DIR=C:/msys64/ucrt64" +Write-Host "" +Write-Host "OpenSSL include:" +Write-Host "C:\msys64\ucrt64\include" +Write-Host "" +Write-Host "OpenSSL libs:" +Write-Host "C:\msys64\ucrt64\lib\libssl.dll.a" +Write-Host "C:\msys64\ucrt64\lib\libcrypto.dll.a" +Write-Host "============================================================" \ No newline at end of file diff --git a/linux_shell/3rd/elfutils b/linux_shell/3rd/elfutils new file mode 100644 index 0000000..c5348bd --- /dev/null +++ b/linux_shell/3rd/elfutils @@ -0,0 +1,50 @@ +#!/bin/bash + +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ./global.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; + source ./../gcc/global.bash +fi + +load_compile_environment() { + load_library "gcc-14.2.0:mpc-1.3.1:mpfr-4.2.1:gmp-6.2.1:cmake-3.26.5:make-4.4:patchelf-0.18.0" + export LD_LIBRARY_PATH=/home/env/Qt5.14.2/5.14.2/gcc_64/lib/:$LD_LIBRARY_PATH +} +load_compile_environment + +_install_="" +_src_="" + +if [[ "$(uname)" == "Linux" ]]; then + echo "This is Linux." + _install_="/ae/install" + _src_="/ae/src" +elif [[ "$(uname)" == "MINGW"* || "$(uname)" == "CYGWIN"* ]]; then + echo "This is Windows (Cygwin or MinGW)." + _install_="D:\wyc\cached_external_library\bash_install" + _src_="D:\wyc\cached_external_library\bash_srcs" +else + echo "Unknown system." +fi + + + +packageName="elfutils" +version="0.189" +_src="${_src_}/${packageName}-${version}" +_build="${_src_}/${packageName}-${version}-build" +_install="${_install_}/${packageName}-${version}-install" + +#wget -P "${src}" https://sourceware.org/elfutils/ftp/0.189/elfutils-0.189.tar.bz2 +tar -xvf "${_src_}/elfutils-0.189.tar.bz2" -C "${_src_}" +chmod 777 "${_src}" +mkdir -m 777 "${_build}" +cd "${_build}" || exit +../"${_src}"/configure --prefix="${_install}" +make -j"$(nproc)" +sudo make install +sudo chmod -R 777 "${_install}" diff --git a/linux_shell/3rd/openssh.bash b/linux_shell/3rd/openssh.bash new file mode 100644 index 0000000..4e8252f --- /dev/null +++ b/linux_shell/3rd/openssh.bash @@ -0,0 +1,44 @@ +#!/bin/bash + +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; + source ../base/export.bash +fi +include "${BASH_SOURCE[0]}" ../base/export.bash + + + +build_python() { + + return 0 +} + + + + +build_open_ssh(){ + build_dir=/ae/env + zlib_ver=zlib-1.3.1 + zlib_dir=${build_dir}/${zlib_ver} + openssh_ver=openssh_10.0p1 + openssh_dir=${build_dir}/${openssh_ver} + + + build_gnu_zip "https://zlib.net/zlib-1.3.1.tar.gz" \ + --prefix=${zlib_dir} + + + # openssl zlib + # --with-privsep-path OpenSSH 的“特权分离(Privilege Separation)目录 + build_gnu_zip "https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-10.0p1.tar.gz" \ + --prefix=${openssh_dir} \ + --with-zlib=${zlib_dir} \ + --with-privsep-path=${openssh_dir}/var/empty + + return 0 +} \ No newline at end of file diff --git a/linux_shell/3rd/patchelf b/linux_shell/3rd/patchelf new file mode 100644 index 0000000..2bbd015 --- /dev/null +++ b/linux_shell/3rd/patchelf @@ -0,0 +1,25 @@ +#!/bin/bash + +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../base/export.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; + source ../base/export.bash +fi + + +packageName="patchelf" +version="0.15.0" +_src="${_src_}/${packageName}-${version}" +_install="${_install_}/${packageName}-${version}" + +git clone --branch "${version}" https://github.com/NixOS/patchelf.git "${_src}" +cd "${_src}" || exit +./bootstrap.sh +./configure --prefix="${_install}" +make -j"$(nproc)" +sudo make install +sudo chmod -R 777 "${_install}" diff --git a/linux_shell/3rd/patchelf.sh b/linux_shell/3rd/patchelf.sh new file mode 100644 index 0000000..6da954b --- /dev/null +++ b/linux_shell/3rd/patchelf.sh @@ -0,0 +1,41 @@ +#!/bin/bash +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi + +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; + source ../base/export.bash +fi + +include "${BASH_SOURCE[0]}" ../base/export.bash + + +if pragma_once "${BASH_SOURCE[0]}"; then + load_compile_environment() { + load_library "gcc-14.2.0:mpc-1.3.1:mpfr-4.2.1:gmp-6.2.1:cmake-3.26.5:make-4.4" + } + load_compile_environment + git clone https://github.com/NixOS/patchelf.git "${_src_}/patchelf-0.18.0" + cd "$_src_/patchelf-0.18.0" || { + echo "$_src_/patchelf-0.18 不存在!" + exit 1 + } + git checkout 0.18.0 + ./bootstrap.sh + ./configure --prefix="${_install_}/patchelf-0.18.0" + make -j"$(nproc)" + make check + sudo make install + sudo chmod -R 777 "${_install_}/patchelf-0.18.0" + patchelf --version +fi + +# /ae/win/wyc/projects/CLionProjects/plantSunCat/0_linux_pro + +#./bootstrap.sh +#./configure +#make +#make check +#sudo make install diff --git a/linux_shell/3rd/sshpass/build b/linux_shell/3rd/sshpass/build new file mode 100644 index 0000000..cf0cc02 --- /dev/null +++ b/linux_shell/3rd/sshpass/build @@ -0,0 +1,3 @@ + + +sshpass -V \ No newline at end of file diff --git a/linux_shell/build_script/Qt/core.bash b/linux_shell/build_script/Qt/core.bash new file mode 100644 index 0000000..934b634 --- /dev/null +++ b/linux_shell/build_script/Qt/core.bash @@ -0,0 +1,240 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" >/dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}" + } +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then + return 0 +fi +include "${BASH_SOURCE[0]}" ../base/export.bash +false && source ../base/export.bash +patch_cross_qt() { + local SYSROOT="${1}" + local CMAKE_DIR="${2}" + check_directory "${SYSROOT}" + check_directory "${CMAKE_DIR}" + local CMAKE_CURRENT_LIST_DIR="${CMAKE_DIR}/Qt5" + check_directory "${CMAKE_CURRENT_LIST_DIR}" + local exclude_list="${CMAKE_CURRENT_LIST_DIR}/Qt5Config.cmake" + local QT5_DIR_LIST="" + for d in "$CMAKE_DIR"/Qt5*; do + [[ -d "$d" ]] || continue + QT5_DIR_LIST+="${d}," + done + QT5_DIR_LIST="${QT5_DIR_LIST%,}" + replace_in_tree \ + "${QT5_DIR_LIST}" \ + "\"/${SYSROOT}" \ + '"${_psc_sys_root}' \ + "${exclude_list}" + local rel_path=$(realpath --relative-to="${CMAKE_CURRENT_LIST_DIR}" "${SYSROOT}") + insert_after_match \ + "${CMAKE_DIR}/Qt5/Qt5Config.cmake" \ + 'get_filename_component[(]_qt5_install_prefix.*[)]' \ + " + if(CMAKE_SYSROOT) + set(_psc_sys_root \"\${CMAKE_SYSROOT}\") + message(STATUS \"CMAKE_SYSROOT:psc_sys_root = \${_psc_sys_root} at \${CMAKE_CURRENT_LIST_FILE} \") + else() + set(_psc_sys_root \${CMAKE_CURRENT_LIST_DIR}/${rel_path}) + message(STATUS \"psc_sys_root = \${_psc_sys_root} at \${CMAKE_CURRENT_LIST_FILE} \") + endif() + " +} +export bq_ver="v5.15.2" +export bq_suffix_opts="" +export bq_install_prefix="ae/Qt/v5.15.2" +# 交叉编译的选项 +export bq_cross="0" +# 这个选项时目录名称 在@/qtbase/mkspecs下 + +#host +export bq_platform="linux-g++" +#target +export bq_xplatform="linux-aarch64-gnu-g++" +export bq_sysroot="" +# 交叉编译使用的host工具qt版本 和目标qt版本 一致 +export bq_host_tool_install_prefix="" +export bq_host_triplet="" +export bq_target_triplet="" +export bq_host_tool_suffix_opts="" +export bq_host_platform="" + + +build_qt_host_tools() { + local src_dir="" + local opts="" + ensure_repo_version src_dir "Qt" "${bq_ver}" + exec_record_fast_fail "cd \"${src_dir}\"" + exec_record_fast_fail "git submodule status --recursive" + exec_record_fast_fail "git submodule update --init --recursive" + check_platform "${src_dir}" "${bq_host_platform}" + check_directory "$(dirname "${bq_host_tool_install_prefix}")" + opts=" \ + -opensource -confirm-license \ + -release \ + -xplatform ${bq_host_platform} \ + -prefix \"${bq_host_tool_install_prefix}\" \ + -make tools -nomake examples -nomake tests \ + -c++std c++14 \ + -no-gui \ + -no-widgets \ + -no-dbus \ + -no-opengl \ + -no-egl \ + -no-openssl \ + -no-icu \ + -no-glib \ + -skip qtdoc \ + -device-option CROSS_COMPILE=${bq_host_triplet}- \ + ${bq_host_tool_suffix_opts} \ + " + configure_gnu_ex "${src_dir}/qtbase" "${opts}" + exec_record "make -j $(nproc)" + exec_record "make install -j $(nproc)" + if [ ! -d "${bq_host_tool_install_prefix}/bin" ]; then + echo "host tool build failed: ${bq_host_tool_install_prefix}/bin not found" >&2 + return 1 + fi + if [ ! -x "${bq_host_tool_install_prefix}/bin/moc" ]; then + echo "host tool build failed: moc not found in ${bq_host_tool_install_prefix}/bin" >&2 + return 1 + fi + if [ ! -x "${bq_host_tool_install_prefix}/bin/rcc" ]; then + echo "host tool build failed: rcc not found in ${bq_host_tool_install_prefix}/bin" >&2 + return 1 + fi + if [ ! -x "${bq_host_tool_install_prefix}/bin/uic" ]; then + echo "host tool build failed: uic not found in ${bq_host_tool_install_prefix}/bin" >&2 + return 1 + fi + echo "host tools installed at: ${bq_host_tool_install_prefix}/bin" + return 0 +} + + +get_qt_platform_from_triplet() { + local triplet="${1}" + local cpu vendor os abi + parse_triplet "$triplet" cpu vendor os abi +} +get_platform_list() { + local -n list="$1" + local src_dir="$2" + local base_dir="$src_dir/qtbase/mkspecs" + local dir + list=() + [ -d "$base_dir" ] || return 1 + for dir in "$base_dir"/*; do + [ -d "$dir" ] || continue + list+=("$(basename "$dir")") + done + return 0 +} +print_platform_list() { + local src_dir="$1" + local platforms=() + local item + get_platform_list platforms "$src_dir" || return 1 + for item in "${platforms[@]}"; do + printf '%s\n' "$item" + done + return 0 +} +check_platform() { + local src_dir="$1" + local platform="$2" + local base_dir="$src_dir/qtbase/mkspecs" + if [ ! -d "$base_dir" ]; then + printf 'mkspecs 目录不存在: %s\n' "$base_dir" >&2 + return 1 + fi + if [ -z "$platform" ]; then + printf 'platform 不能为空\n' >&2 + return 1 + fi + if [ -d "$platform" ]; then + if [ "$(dirname "$platform")" = "$base_dir" ]; then + return 0 + fi + printf 'platform 不属于当前源码树: %s\n' "$platform" >&2 + return 1 + fi + if [ -d "$base_dir/$platform" ]; then + return 0 + fi + printf 'platform 不存在: %s\n' "$platform" >&2 + printf '可用 platform 列表:\n' >&2 + print_platform_list "$src_dir" >&2 + return 1 +} +# TODO: cross qt 还需要改路径 +build_qt() { + src_dir="" + ensure_repo_version src_dir "Qt" "${bq_ver}" + exec_record_fast_fail "cd \"${src_dir}\"" + exec_record_fast_fail "git submodule status --recursive" + exec_record_fast_fail "git submodule update --init --recursive" + local opts + opts=" \ + -opensource -confirm-license \ + -nomake tests \ + -nomake examples \ + -skip qtwebengine \ + -skip qtdocgallery \ + ${bq_suffix_opts} \ + " + if [[ "$bq_cross" == "1" ]]; then + check_directory_var bq_sysroot + check_platform "${src_dir}" "${bq_platform}" + check_platform "${src_dir}" "${bq_xplatform}" + if [ -z "$bq_host_tool_install_prefix" ]; then + bq_host_tool_install_prefix="${bq_install_prefix}/host" + log_info "build_qt_host_tools ${bq_host_tool_install_prefix}" + mkdir -p "${bq_host_tool_install_prefix}" + build_qt_host_tools + else + log_info "build_qt_host_tools at [${bq_host_tool_install_prefix}] exist skip " + fi + + opts=" \ + -sysroot \"${bq_sysroot}\" \ + -external-hostbindir \"${bq_host_tool_install_prefix}/bin\" \ + -platform ${bq_platform} \ + -xplatform ${bq_xplatform} \ + -prefix \"${bq_sysroot}\" \ + -extprefix \"${bq_install_prefix}\" \ + -hostprefix \"${bq_install_prefix}/host\" \ + -c++std c++14 \ + -device-option CROSS_COMPILE=${bq_host_triplet}- \ + ${opts}" + # sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix + # sudo update-alternatives --set x86_64-w64-mingw32-gcc /usr/bin/x86_64-w64-mingw32-gcc-posix + # TODO: platform 是win 才传入 + else + opts=" \ + -prefix \"${bq_install_prefix}\" \ + ${opts}" + fi + # exec_record "which ${bq_host_triplet}-g++" + # exec_record "${bq_host_triplet}-g++ -v" + # exec_record "which ${bq_host_triplet}-gcc" + # exec_record "${bq_host_triplet}-gcc -v" + # + # + # + # + # export CC="${bq_host_triplet}-gcc" + # export CXX="${bq_host_triplet}-g++" + configure_gnu_ex "$src_dir" "${opts}" + exec_record "make -j $(nproc)" + exec_record "make install -j $(nproc)" + if [[ "$bq_cross" == "1" ]]; then + patch_cross_qt "${bq_sysroot}" "${bq_install_prefix}/lib/cmake" + fi +} + + diff --git a/linux_shell/build_script/Qt/export.bash b/linux_shell/build_script/Qt/export.bash new file mode 100644 index 0000000..67c550b --- /dev/null +++ b/linux_shell/build_script/Qt/export.bash @@ -0,0 +1,16 @@ +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi + + + + +include "${BASH_SOURCE[0]}" ./core.bash +# shellcheck source=./core.bash + + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/attach/core.bash b/linux_shell/build_script/attach/core.bash new file mode 100644 index 0000000..8b2fe90 --- /dev/null +++ b/linux_shell/build_script/attach/core.bash @@ -0,0 +1,438 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi + +include "${BASH_SOURCE[0]}" ../base/export.bash +false && source ../base/export.bash + + +include "${BASH_SOURCE[0]}" ../gcc/export.bash +false && source ../gcc/export.bash + + +include "${BASH_SOURCE[0]}" ../Qt/export.bash +false && source ../Qt/export.bash + + + + +# gcc_env +export gev_target_env +export gev_target_sysroot +export gev_cross_dir +export gev_canadian_dir +export gev_stage1_dir +export gev_local_dir +export gev_cur_env_name +export gev_cur_toolchain_name +# 构建sysroot所需 +export gev_linux_ver # 下载linux 内核源码的 url +export gev_linux_arch # linux arch架构名称 +export gev_glibc_ver gev_glibc_suffix_opts +export gev_stage1_gcc_ver gev_stage1_gcc_suffix_opts +# 自动计算 +export gev_local_triplet gev_local_triplet_no_vendor +export gev_target +export gev_build + + +# 这个函数不能放到gcc编译的开头因为gcc编译的开头需要外部的参数 如果设置了外部参数就失效了 +gev_init_params() { + gev_target_env="" + gev_target_sysroot="" + gev_cross_dir="" + gev_canadian_dir="" + gev_stage1_dir="" + gev_local_dir="" + gev_cur_env_name="" + gev_cur_toolchain_name="" + gev_linux_ver="v5.15.139" + gev_linux_arch="x86_64" + gev_glibc_ver="glibc-2.31" + gev_glibc_suffix_opts="" + gev_stage1_gcc_ver="releases/gcc-10.5.0" + gev_stage1_gcc_suffix_opts="" +} +# 初始化全局变量参数值 +gev_init_params +init_by_env_name() { + detect_platform_triplet gev_local_triplet gev_local_triplet_no_vendor + gev_build=${gev_local_triplet} + gev_cur_env_name="${1}" + gev_cur_toolchain_name="${gev_cur_env_name}" + gev_target="${2}" + gev_target_env="/ae/env/${gev_cur_env_name}" + # 这个地方可以改 sysroot 叫什么名称 + gev_target_sysroot="${gev_target_env}/sysroot_${gev_target}" + gev_cross_dir="${gev_target_env}" + gev_canadian_dir="${gev_target_env}" + gev_stage1_dir="${gev_target_env}/stage1" + gev_local_dir="${gev_target_env}/local" + check_and_create_dir "$gev_target_sysroot" + # 设置当前日志路径 + LOG_PATH="${gev_target_env}/build.log" + log_info "init_by_env_name ok!" +} + + +cacl_toolchain_name(){ + local -n ret="$1" + local build="$2" + local host="$3" + local target="$4" + local ver="$5" + ver="${ver//\//_}" + ret="${ver}_${host}" +} + +cacl_toolchain_name_cross(){ + local ver="$2" + cacl_toolchain_name "${1}" "${gev_build}" "${gev_build}" "${gev_target}" "${ver}" +} + +# env_name source_sysroot +init_env() { + init_by_env_name "${1}" "${3}" + local source_sysroot="${2}" + # cp -a "$source_sysroot/." "$gev_target_sysroot/" + if [[ -d "$gev_target_sysroot" ]] && [[ "$(ls -A "$gev_target_sysroot" 2>/dev/null)" ]]; then + log_info "sysroot already exists, skip copy: $gev_target_sysroot\n" + else + log_info "copy sysroot: [$source_sysroot] -> [$gev_target_sysroot]\n" + mkdir -p "$gev_target_sysroot" + check_directory_var source_sysroot + cp -a "$source_sysroot/." "$gev_target_sysroot/" + +# rsync -aH --numeric-ids \ +# --exclude='/dev/*' \ +# --exclude='/proc/*' \ +# --exclude='/sys/*' \ +# --exclude='/run/*' \ +# "$source_sysroot/" \ +# "$gev_target_sysroot/" + + +# rsync -aH --numeric-ids \ +# --include='/usr/' \ +# --include='/usr/include/***' \ +# --include='/usr/lib/***' \ +# --include='/lib/***' \ +# --include='/lib64/***' \ +# --include='/etc/' \ +# --include='/etc/ld.so.conf' \ +# --include='/etc/ld.so.conf.d/***' \ +# --exclude='*' \ +# "$source_sysroot/" \ +# "$gev_target_sysroot/" + +# rsync -aH --numeric-ids \ +# --include='/usr/' \ +# --include='/usr/include/***' \ +# --include='/usr/lib/' \ +# --include="/usr/lib/${bge_target}/***" \ +# --include='/usr/lib/gcc/' \ +# --include="/usr/lib/gcc/${bge_target}/***" \ +# --include='/lib/' \ +# --include="/lib/${bge_target}/***" \ +# --include='/lib64/***' \ +# --include='/etc/' \ +# --include='/etc/ld.so.conf' \ +# --include='/etc/ld.so.conf.d/***' \ +# --exclude='*' \ +# "$source_sysroot/" \ +# "$gev_target_sysroot/" + + #copy_compile_sysroot_files "$source_sysroot" "$gev_target_sysroot" "$bge_target" + + fi + log_info "env initialized: env=[${gev_target_env}] sysroot=[${gev_target_sysroot}]\n" +} + +attach_env_stage1_gcc() { + log_info "attach_env_stage1_gcc start" + local target="$1" + local local_triplet local_triplet_no_vendor + detect_platform_triplet local_triplet local_triplet_no_vendor + bge_gcc_ver="${gev_stage1_gcc_ver}" + bge_stage1=1 + bge_install_prefix="${gev_stage1_dir}/gcc_stage1_${target}" + bge_build="$local_triplet" + bge_host="$local_triplet" + bge_target="$target" #注意这一点 即使是cross 编译 stage1 gcc 永远是本机gcc + bge_sysroot_use_mode="link" + bge_source_sysroot="$bge_install_prefix/sysroot" + bge_toolchain_name="${gev_cur_toolchain_name}" + check_and_create_dir "${bge_source_sysroot}" + build_gcc_ex + log_info "attach_env_stage1_gcc end" +} + + + +# env_name target 选项没配置对 目前编译到 glibc checking host system type... Invalid configuration `aarch64-linux-gnu': machine `aarch64' not recognized +init_env_build_sysroot() { + + # https://stackoverflow.com/questions/28904902/how-do-i-change-gccs-default-search-directory-for-crti-o?utm_source=chatgpt.com + # https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.html?utm_source=chatgpt.com + # https://gcc.gnu.org/onlinedocs/gccint/Driver.html?utm_source=chatgpt.com + # 第一处是 GCC 的 spec 机制文档。官方明确写了: + # %S:处理 startfile spec,也就是“决定哪些对象文件作为最先传给 linker 的文件”,典型就是 crt0.o、crt1.o、crti.o 这类启动文件。 + # %E:处理 endfile spec,也就是“决定哪些对象文件作为最后传给 linker 的文件”,典型就是 crtn.o 这类收尾文件。 + # 第二处是 GCC Internals 的 Driver 文档。里面把这些宏的职责写得更直接: + # STARTFILE_SPEC 指定标准 C startup file。 + # ENDFILE_SPEC 指定标准 C end file。 + # 文档还说明,如果没有定义这些宏,就会用默认值。 + # 这意味着: + # crti.o、crt1.o 这类不是普通 -lxxx 库 + # 它们走的是 STARTFILE_SPEC + # crtn.o 这类走的是 ENDFILE_SPEC + # 所以它们和 -lc、-lm 这类普通库的搜索规则不是一回事 + # /ae/bash/0_git_cache_dir/gcc/build/gcc/specs + + + init_by_env_name "${1}" + local target="${2}" + local t_cpu t_vendor t_os t_abi + parse_triplet "$target" t_cpu t_vendor t_os t_abi + + local linuxarch=$t_cpu + if [[ $linuxarch == "aarch64" ]]; then + linuxarch="arm64" + elif [[ $linuxarch =~ i[3-6]86 ]]; then + linuxarch="x86" + elif [[ $linuxarch != x86_64 ]]; then + linuxarch="${linuxarch%%[0-9]*}" + fi + # 参数检查:确保必要参数存在 + if [[ -z "$target" ]]; then + log_error "ERROR: target is required for init_env_build_sysroot\n" + exit 1 + fi + local build_triplet build_triplet_no_vendor + detect_platform_triplet build_triplet build_triplet_no_vendor + ( + log_info "step 1 stage1_gcc构建失败 Starting kernel header installation...\n" + attach_env_stage1_gcc "${target}" + ) + check_ret_exit "stage1_gcc构建失败!" + ( + log_info "step 2 安装内核头文件 Starting kernel header installation... ${linuxarch} ${gev_linux_ver}\n" + local install_prefix="${gev_target_sysroot}/usr" + local src_dir + ensure_repo_version src_dir "linux" "${gev_linux_ver}" + cd $src_dir || exit 89 + check_and_create_dir "${install_prefix}" + exec_record "make headers_install ARCH=${linuxarch} -j$(nproc) INSTALL_HDR_PATH=\"${install_prefix}\"" + ) + check_ret_exit "安装内核头文件失败!" + ( + load_toolchains_under "$gev_stage1_dir" + local glibc_triplet + local glibc_cpu="${t_cpu}" + compose_triplet glibc_triplet "${glibc_cpu}" "" "${t_os}" "${t_abi}" + log_info "glibc_triplet ${glibc_triplet}\n" + local glibc_opts="\ + --build=${build_triplet} \ + --host=${target} \ + --with-headers=${gev_target_sysroot}/usr/include \ + --prefix=/usr \ + --disable-werror \ + --disable-nls \ + ${gev_glibc_suffix_opts}" + log_info " step 3 编译glibc Compiling glibc with options: $gev_target_sysroot\n" + log_info " glibc_opts: $glibc_opts\n" + local src_dir + ensure_repo_version src_dir "glibc" "${gev_glibc_ver}" + configure_gnu_ex "${src_dir}" "$glibc_opts" + exec_record_fast_fail "make -j $(nproc)" + exec_record_fast_fail "make -h" + exec_record_fast_fail "make install install_root=$gev_target_sysroot -j $(nproc)" + + local src_dir="${gev_target_sysroot}/usr/lib64" + local dest_dir="${gev_target_sysroot}/lib" + check_directory "${src_dir}" + check_directory "${dest_dir}" + local array=(crt1.o crti.o crtn.o gcrt1.o Scrt1.o rcrt1.o) + log_info "cp [${array[*]}] ${src_dir} ==> ${dest_dir} " + for f in "${array[@]}"; do + local src_file="$src_dir/$f" + if [ -e "$src_file" ]; then + echo "copy $f" + cp -f "$src_file" "${dest_dir}" + fi + done + + + ) + check_ret_exit "glibc 安装失败" + log_info " 自构建sysroot环境搭建完成 env initialized: env=${gev_target_env} sysroot=${gev_target_sysroot}\n" +} + + +cacl_toolchain_name_canadian(){ + local host="$2" + local ver="$3" + cacl_toolchain_name "${1}" "${gev_build}" "${host}" "${gev_target}" "${ver}" +} + +# target ver +attach_env_local_cross() { + log_info "attach_env_local_cross start" + local ver="$1" + local target="$gev_target" + [[ -z "$target" ]] && log_error "ERROR: target required\n" && exit 1 + [[ -z "$ver" ]] && log_error "ERROR: ver required\n" && exit 1 + ( + [[ ! -d "$gev_target_sysroot" ]] && log_error "ERROR: env sysroot not found: $gev_target_sysroot\n" && exit 1 + bge_build="$gev_local_triplet" + bge_host="$gev_local_triplet" + bge_target="$target" + local toolchain_name + cacl_toolchain_name_cross toolchain_name "${ver}" + bge_install_prefix="${gev_cross_dir}/${toolchain_name}" + bge_source_sysroot="$gev_target_sysroot" + bge_sysroot_use_mode="link" + bge_gcc_ver="${ver}" + bge_toolchain_name="${gev_cur_toolchain_name}" + build_gcc_ex + ) + log_info "attach_env_local_cross end" +} + +load_toolchains_under() { + local base="$1" + [[ -d "$base" ]] || return 0 + + local prefix trip + + # base 下每个子目录当作一个工具链 prefix(例如 cross/gcc_xxx 或 canadian/gcc_xxx) + for prefix in "$base"/*; do + [[ -d "$prefix" ]] || continue + [[ -d "$prefix/bin" ]] || continue + + # prefix 下可能有 triplet 目录(aarch64-xxx-gnu 这类) + for trip in "$prefix"/*; do + [[ -d "$trip" ]] || continue + local n + n="$(basename "$trip")" + + # 跳过常见非 triplet 目录 + case "$n" in + bin | lib | lib64 | include | share | etc | var | tmp | sysroot | cross | canadian | libexec) continue ;; + esac + load_toolchain "$prefix" "$n" + log_info "loaded toolchain: prefix=$prefix triplet=$n\n" + # 满足目录形态才加载 + if [[ -d "$prefix/$n/usr" || -d "$prefix/$n/sysroot/usr" || -d "$prefix/$n/sysroot/lib" ]]; then + load_toolchain "$prefix" "$n" + log_info "loaded toolchain: prefix=$prefix triplet=$n\n" + fi + done + done +} + +# sudo apt install -y mingw-w64 gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 +# 注意这个函数调用前需要加载 前两个交叉编译环境 默认的windows "x86_64-w64-mingw32" +# host target ver +# TODO: host是windows时 要编译mingw运行时库 和 移动 gmp mpc mpfr等库 到 ${root}/bin 里去 +attach_env_canadian_stage3() { + log_info "attach_env_canadian_stage3 start" + local host="$1" + local ver="$2" + local target="$gev_target" + bge_build="$gev_local_triplet" + bge_host="$host" + bge_target="$target" + local toolchain_name + + local toolchain_name + cacl_toolchain_name_canadian toolchain_name "${host}" "${ver}" + bge_install_prefix="${gev_canadian_dir}/${toolchain_name}" + ( + local target_toolchain_name host_toolchain_name + cacl_toolchain_name_cross target_toolchain_name "${ver}" + cacl_toolchain_name host_toolchain_name "${bge_build}" "${bge_build}" "${bge_host}" "${ver}" + local target_tool_chain="${gev_cross_dir}/${target_toolchain_name}" + local host_tool_chain="${gev_cross_dir}/${host_toolchain_name}" + if [[ -d "$target_tool_chain" ]]; then + load_toolchain "${target_tool_chain}" "${target}" + else + log_warn "target_tool_chain not exists: $target_tool_chain" + fi + if [[ -d "$host_tool_chain" ]]; then + load_toolchain "${host_tool_chain}" "${host}" + else + log_warn "host_tool_chain not exists: $host_tool_chain" + fi + bge_source_sysroot="$gev_target_sysroot" + bge_sysroot_use_mode="link" + bge_gcc_ver="${ver}" + bge_toolchain_name="${gev_cur_toolchain_name}" + build_gcc_ex + ) + log_info "attach_env_canadian_stage3 end" +} + + +attach_host_tool_qt(){ + bq_sysroot="${gev_target_sysroot}" + bq_cross=0 + bq_install_prefix="${gev_local_dir}/Qt/${bq_ver}" + build_qt +} + + +attach_cross_tool_qt(){ + bq_sysroot="${gev_target_sysroot}" + bq_cross=1 + bq_host_tool_install_prefix="${gev_local_dir}/Qt/${bq_ver}" + bq_platform="linux-g++" + bq_xplatform="linux-aarch64-gnu-g++" + bq_install_prefix="${gev_cross_dir}/Qt/${bq_xplatform}/${bq_ver}" + + log_info "attach_cross_tool_qt ${bq_install_prefix}" + + build_qt +} + +attach_cross_win_qt(){ + bq_sysroot="${gev_target_sysroot}" + bq_cross=1 + + bq_platform="linux-g++" + bq_xplatform="linux-aarch64-gnu-g++" + bq_host_platform="win32-g++" + bq_install_prefix="${gev_target_env}/Qt/${bq_host_platform}_${bq_xplatform}/${bq_ver}" + + bq_host_triplet="x86_64-w64-mingw32" + bq_target_triplet="aarch64-linux-gnu" + local h_cpu h_vendor h_os h_abi + local t_cpu t_vendor t_os t_abi + parse_triplet "${bq_host_triplet}" h_cpu h_vendor h_os h_abi + parse_triplet "${bq_target_triplet}" t_cpu t_vendor t_os t_abi + log_info "host cpu[${h_cpu}] vendor[${h_vendor}] os[${h_os}] abi[${h_abi}] \n" + log_info "target cpu[${t_cpu}] vendor[${t_vendor}] os[${t_os}] abi[${t_abi}] \n" + + log_info "attach_cross_tool_qt ${bq_install_prefix}" + build_qt +} + +attach_win_2_arm_qt(){ + bq_sysroot="${gev_target_sysroot}" + bq_cross=1 + bq_host_tool_install_prefix="${gev_local_dir}/Qt/${bq_ver}" + bq_platform="linux-g++" + bq_xplatform="linux-aarch64-gnu-g++" + bq_install_prefix="${gev_cross_dir}/Qt/${bq_xplatform}/${bq_ver}" + + log_info "attach_cross_tool_qt ${bq_install_prefix}" + + build_qt +} + diff --git a/linux_shell/build_script/attach/export.bash b/linux_shell/build_script/attach/export.bash new file mode 100644 index 0000000..67c550b --- /dev/null +++ b/linux_shell/build_script/attach/export.bash @@ -0,0 +1,16 @@ +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi + + + + +include "${BASH_SOURCE[0]}" ./core.bash +# shellcheck source=./core.bash + + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/cacl.bash b/linux_shell/build_script/base/cacl.bash new file mode 100644 index 0000000..33c5f52 --- /dev/null +++ b/linux_shell/build_script/base/cacl.bash @@ -0,0 +1,47 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash + + + + +square() { + echo $(($1 * $1)) +} + +cube() { + echo $(($1 * $1 * $1)) +} + +add() { + echo $(($1 + $2)) +} + +map() { + local fn=$1 + while read value; do + $fn $value + done +} + +reduce() { + local fn=$1 + local result=${2:-0} # 初始值 + while read value; do + result=$($fn $result $value) + done + echo $result +} + +#seq 1 10 | map square | reduce add # 平方和:385 +#seq 1 10 | map cube | reduce add # 立方和:3025 + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/check.bash b/linux_shell/build_script/base/check.bash new file mode 100644 index 0000000..ff2af80 --- /dev/null +++ b/linux_shell/build_script/base/check.bash @@ -0,0 +1,11 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash \ No newline at end of file diff --git a/linux_shell/build_script/base/common.bash b/linux_shell/build_script/base/common.bash new file mode 100644 index 0000000..ec32a1a --- /dev/null +++ b/linux_shell/build_script/base/common.bash @@ -0,0 +1,175 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash + + +exec_record() { + local cmd="$1" + local start_time=$(date '+%Y-%m-%d %H:%M:%S.%3N') + local start_ts=$(date +%s.%3N) + log_info "[$(pwd)] exec: $cmd " + eval "$cmd" + local ret=$? + local end_time=$(date '+%Y-%m-%d %H:%M:%S.%3N') + local end_ts=$(date +%s.%3N) + local duration=$(awk "BEGIN {print $end_ts - $start_ts}") + if [ $ret -ne 0 ]; then + local pretty_cmd=$(printf '%s\n' "$cmd" | sed 's/ --/\n--/g') + log_error "$(pwd):cmd failed: $pretty_cmd, duration ${duration}s" + else + log_info "ok duration ${duration}s" + fi + return $ret +} + +exec_record_fast_fail() { + local cmd="$1" + local log_file="$LOG_PATH" + local start_time + local start_ts + local end_time + local end_ts + local duration + local ret + local pretty_cmd + + start_time=$(date '+%Y-%m-%d %H:%M:%S.%3N') + start_ts=$(date +%s.%3N) + + log_info "[$(pwd)] exec: $cmd" + + { + echo "[CMD-BEGIN] $start_time" + echo "[PWD] $(pwd)" + echo "[CMD] $cmd" + eval "$cmd" + ret=$? + echo "[CMD-END] ret=$ret" + exit $ret + } 2>&1 | tee -a "$log_file" + + ret=${PIPESTATUS[0]} + + end_time=$(date '+%Y-%m-%d %H:%M:%S.%3N') + end_ts=$(date +%s.%3N) + duration=$(awk "BEGIN {print $end_ts - $start_ts}") + + if [ $ret -ne 0 ]; then + pretty_cmd=$(printf '%s\n' "$cmd" | sed 's/ --/\n--/g') + log_error "$(pwd):cmd failed: $pretty_cmd, duration ${duration}s" + else + log_info "ok duration ${duration}s" + fi + + return $ret +} + + +exec_record_fast_fail_no_log() { + local cmd="$1" + exec_record "$cmd" + local ret=$? + if [ $ret -ne 0 ]; then + exit $ret + fi +} + + +append_rpath() { + if [ -z "$1" ] || [ -z "$2" ]; then + echo "Usage: update_rpath " + return 1 + fi + DIR_PATH="$1" + RPATH_VALUE="$2" + if [ ! -d "$DIR_PATH" ]; then + echo "Error: Directory '$DIR_PATH' does not exist." + return 1 + fi + find "$DIR_PATH" -type f -exec file {} \; | grep -E 'ELF|shared object' | while read -r line; do + #find "$DIR_PATH" -type f ! -name "*.o" | parallel file {} | grep -E 'ELF|shared object' | while read -r line; do + FILE_PATH=$(echo "$line" | cut -d: -f1) + RPATH=$(readelf -d "$FILE_PATH" | grep -i rpath) + if [ ! -z "$RPATH" ]; then + CURRENT_RPATH=$(readelf -d "$FILE_PATH" | grep -i rpath | awk '{print $2}' | tr -d '[]') + NEW_RPATH="$CURRENT_RPATH:$RPATH_VALUE" + else + NEW_RPATH="$RPATH_VALUE" + fi + patchelf --set-rpath "$NEW_RPATH" "$FILE_PATH" + # 验证修改是否成功 + if [ $? -eq 0 ]; then + echo "Updated rpath for: $FILE_PATH" + else + echo "Error: Failed to update rpath for $FILE_PATH" + fi + done +} + + +merge_args(){ + local -n ret=$1 + local t=$2 + local list="" + shift 2 + for param in "$@"; do + list="${list}${list:+$t}$param" + done + ret="$list" +} + + + +#load_toolchain() { +# p=$1 # 工具链根路径 +# n=$2 # 工具链架构名三元组 +# local d="${p}/${n}" +# local d2="${p}/${n}/usr" +# +# local libs="$d2/lib:$d2/lib64:${p}/lib:${p}/lib64" +# # exe运行时查找库的路径 +# export LD_LIBRARY_PATH="$libs${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" +# export LIBRARY_PATH="$libs${LIBRARY_PATH:+:$LIBRARY_PATH}" +# # exe查找路径 +# export PATH="${p}/bin${PATH:+:$PATH}" +#} + +load_toolchain() { + local p="$1" # 工具链根路径(prefix) + local n="$2" # 三元组目录名 + local d="${p}/${n}" + + log_info "load_toolchain path: ${p} 三元组: ${n}" + # 兼容两种布局: + # 1) prefix//usr/... + # 2) prefix//sysroot/usr/... + local d2="${d}/usr" + if [[ ! -d "$d2" && -d "${d}/sysroot/usr" ]]; then + d2="${d}/sysroot/usr" + fi + + # 如果还是不存在,就直接跳过 + local libs + if [[ ! -d "$d2" ]]; then + log_warn "skip load_toolchain: no usr found under ${d2}" + libs="${p}/lib:${p}/lib64" + else + libs="${d2}/lib:${d2}/lib64:${p}/lib:${p}/lib64" + fi + + + export LD_LIBRARY_PATH="${libs}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" + export LIBRARY_PATH="${libs}${LIBRARY_PATH:+:$LIBRARY_PATH}" + export PATH="${p}/bin${PATH:+:$PATH}" + +} + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/compress.bash b/linux_shell/build_script/base/compress.bash new file mode 100644 index 0000000..83fe262 --- /dev/null +++ b/linux_shell/build_script/base/compress.bash @@ -0,0 +1,87 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash + + +extract(){ + local suffix=$1 + local zip_file_path=$2 + local dest_dir=$3 + case "$suffix" in + "tar.gz" | "tgz") + exec_record_fast_fail "tar -xzf $zip_file_path -C $dest_dir" + ;; + "tar.bz2" | "tbz") + exec_record_fast_fail "tar -xjf $zip_file_path -C $dest_dir" + ;; + "tar.xz" | "txz") + exec_record_fast_fail "tar -xJf $zip_file_path -C $dest_dir" + ;; + "zip") + exec_record_fast_fail "unzip $zip_file_path -d $dest_dir" + ;; + "gz") + exec_record_fast_fail "gunzip -c $zip_file_path > $dest_dir" + ;; + "bz2") + exec_record_fast_fail "bunzip2 -c $zip_file_path > $dest_dir" + ;; + *) + echo "Unsupported file format: $suffix" + exit 124 + ;; + esac +} + + +get_suffix() { + local -n ret=$1 + local filename="$(basename "$2")" + local reversed_filename=$(echo "$filename" | rev) + local first_extension=$(echo "$reversed_filename" | cut -d'.' -f1 | rev) + local second_extension=$(echo "$reversed_filename" | cut -d'.' -f2 | rev) + if [ -z "$second_extension" ]; then + ret=$first_extension + else + if [[ "$second_extension" == "tar" ]]; then + if [[ "$first_extension" == "gz" ]]; then + ret="tar.gz" + elif [[ "$first_extension" == "bz2" ]]; then + ret="tar.bz2" + elif [[ "$first_extension" == "xz" ]]; then + ret="tar.xz" + else + echo "tar but not ok first_extension:$first_extension second_extension:$second_extension" + exit 101; + fi + else +# echo "two . but not tar first_extension:$first_extension second_extension:$second_extension" +# exit 102 + ret=$first_extension + fi + fi +} + +package_xz() { + local path=$1 + local dir_path=$(dirname ${path}) + local name=$(basename ${path}) +# echo "$path" +# echo "$dir_path" +# echo "$name" + cd $dir_path + size=$(du -sb "$name" | awk '{print $1}') + #tar --dereference -cf - "$name" | pv -s $size | xz -T0 -3 > "$name.tar.xz" + exec_record_fast_fail "tar --dereference -cf - \"$name\" | pv -s $size | xz -T0 -3 > \"$name.tar.xz\"" +} + + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/container.bash b/linux_shell/build_script/base/container.bash new file mode 100644 index 0000000..a2f7f9c --- /dev/null +++ b/linux_shell/build_script/base/container.bash @@ -0,0 +1,349 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash + + + + + +list_size() { + local list_str=$1 + IFS=":" read -r -a array <<<"$list_str" # 用冒号分割字符串到数组 + _ret_=${#array[@]} # 将数组的大小存入全局变量 _ret_ +} + +list_insert_element() { + local list_str=$1 + local pos=$2 + local element=$3 # 要插入的新元素 + IFS=":" read -r -a array <<<"$list_str" + list_size "$list_str" + local size=$_ret_ + if ((pos < 0 || pos > size)); then + echo "list_insert_element error! pos:${pos} size:${size} list:$list_str" + exit 1 + fi + new_array=("${array[@]:0:pos}" "$element" "${array[@]:pos}") + _ret_=$( + IFS=":" + echo "${new_array[*]}" + ) +} + +list_insert_element_if_not_exist() { + local list_str=$1 + local pos=$2 + local element=$3 + list_find_element "$list_str" "$element" + if [[ $_ret_ != "-1" ]]; then + _ret_="$list_str" + return 0 + fi + list_insert_element "$list_str" "$pos" "$element" +} + +list_append_element() { + local list_str=$1 + local element=$2 + list_size "$list_str" + list_insert_element "$list_str" "$_ret_" "$element" +} + +list_prepend_all_element() { + local list_str=$1 + local element=$2 + local result="" + IFS=":" read -r -a array <<<"$list_str" + for i in "${!array[@]}"; do + result+="$element${array[$i]}:" + done + _ret_="${result%:}" +} + +list_append_all_element() { + local list_str=$1 + local element=$2 + local result="" + IFS=":" read -r -a array <<<"$list_str" + for i in "${!array[@]}"; do + result+="${array[$i]}$element:" + done + _ret_="${result%:}" +} + +list_append_element_if_not_exist() { + local list_str=$1 + local element=$2 + list_size "$list_str" + list_insert_element_if_not_exist "$list_str" "$_ret_" "$element" +} + +list_prepend_element() { + local list_str=$1 + local element=$2 + list_insert_element "$list_str" "0" "$element" +} + +list_prepend_element_if_not_exist() { + local list_str=$1 + local element=$2 + list_insert_element_if_not_exist "$list_str" "0" "$element" +} + +list_remove_at() { + local list_str=$1 + local pos=$2 + IFS=":" read -r -a array <<<"$list_str" + list_size "$list_str" + local size=$_ret_ + if [[ ${size} == 1 ]]; then + _ret_="" + fi + if ((pos < 0 || pos >= size)); then + echo "list_remove_at error! pos:${pos} size:${size} list:$list_str" + exit 1 + fi + new_array=("${array[@]:0:pos}" "${array[@]:pos+1}") + _ret_=$( + IFS=":" + echo "${new_array[*]}" + ) +} + +list_remove_last() { + local list_str=$1 + list_size "$list_str" + local index=$((_ret_ - 1)) + list_remove_at "$list_str" "$index" +} + +list_remove_first() { + local list_str=$1 + list_remove_at "$list_str" "0" +} + +list_find_element_regex() { + local list_str=$1 + local regex=$2 + IFS=":" read -r -a array <<<"$list_str" + local i + for i in "${!array[@]}"; do + if [[ "${array[$i]}" =~ $regex ]]; then + _ret_="$i" + return 0 + fi + done + _ret_="-1" +} + +list_find_element() { + local list_str=$1 + local element=$2 + local regex="^${element}$" + list_find_element_regex "$list_str" "$regex" +} + +list_remove_element_if_exist() { + local list_str=$1 + local element=$2 + list_find_element "$list_str" "$element" + local pos=$_ret_ + if [[ "$pos" == "-1" ]]; then + _ret_="$list_str" + return 0 + fi + list_remove_at "$list_str" "$pos" +} + +# =========================== 测试 =========================== +test_list_size() { + local test_string="apple:banana:cherry:date:grape" + local expected_size=5 + list_size "$test_string" + local size=$_ret_ + if [[ "$size" -ne $expected_size ]]; then + echo "Size test failed:" + echo " Input list: '$test_string'" + echo " Expected: $expected_size" + echo " Got: $size" + exit 1 + fi +} + +test_list_insert_element() { + local test_string="apple:banana:cherry:date:grape" + local insert_pos=2 + local insert_element="orange" + local expected_inserted="apple:banana:orange:cherry:date:grape" + list_insert_element "$test_string" "$insert_pos" "$insert_element" + local inserted=$_ret_ + if [[ "$inserted" != "$expected_inserted" ]]; then + echo "Insert test failed:" + echo " Input list: '$test_string'" + echo " Insert Position: $insert_pos" + echo " Insert Element: '$insert_element'" + echo " Expected: '$expected_inserted'" + echo " Got: '$inserted'" + exit 1 + fi + + # Test inserting into an empty string + local empty_string="" + local expected_inserted_empty="orange" + list_insert_element "$empty_string" 0 "$insert_element" + local inserted_empty=$_ret_ + if [[ "$inserted_empty" != "$expected_inserted_empty" ]]; then + echo "Insert test with empty string failed:" + echo " Input list: '$empty_string'" + echo " Insert Position: 0" + echo " Insert Element: '$insert_element'" + echo " Expected: '$expected_inserted_empty'" + echo " Got: '$inserted_empty'" + exit 1 + fi +} + +test_list_remove_at() { + local test_string="apple:banana:orange:cherry:date:grape" + local remove_pos=1 + local expected_removed_at="apple:orange:cherry:date:grape" + list_remove_at "$test_string" "$remove_pos" + local removed_at=$_ret_ + if [[ "$removed_at" != "$expected_removed_at" ]]; then + echo "Remove at test failed:" + echo " Input list: '$test_string'" + echo " Remove Position: $remove_pos" + echo " Expected: '$expected_removed_at'" + echo " Got: '$removed_at'" + exit 1 + fi +} + +test_list_find_element() { + local test_string="apple:banana:cherry:date:grape" + local find_element="banana" + local expected_find_index=1 + list_find_element "$test_string" "$find_element" + local find_index=$_ret_ + if [[ "$find_index" -ne $expected_find_index ]]; then + echo "Find element test failed:" + echo " Input list: '$test_string'" + echo " Element: '$find_element'" + echo " Expected: $expected_find_index" + echo " Got: $find_index" + exit 1 + fi +} + +test_list_remove_element_if_exist() { + local test_string="apple:banana:cherry:date:grape" + local remove_element="cherry" + local expected_after_remove="apple:banana:date:grape" + list_remove_element_if_exist "$test_string" "$remove_element" + local after_remove=$_ret_ + if [[ "$after_remove" != "$expected_after_remove" ]]; then + echo "Remove '$remove_element' test failed:" + echo " Input list: '$test_string'" + echo " Expected: '$expected_after_remove'" + echo " Got: '$after_remove'" + exit 1 + fi +} + +test_list_remove_non_existent_element() { + local test_string="apple:banana:cherry:date:grape" + local expected_after_not_exist="apple:banana:cherry:date:grape" + list_remove_element_if_exist "$test_string" "pear" + local after_not_exist=$_ret_ + if [[ "$after_not_exist" != "$expected_after_not_exist" ]]; then + echo "Remove 'pear' (not exist) test failed:" + echo " Input list: '$test_string'" + echo " Expected: '$expected_after_not_exist'" + echo " Got: '$after_not_exist'" + exit 1 + fi +} + +test_list_append_element() { + local test_string="apple:banana:cherry:date:grape" + local append_element="new_element" + local expected_appended="apple:banana:cherry:date:grape:new_element" + list_append_element "$test_string" "$append_element" + local appended=$_ret_ + if [[ "$appended" != "$expected_appended" ]]; then + echo "Append test failed:" + echo " Input list: '$test_string'" + echo " Append Element: '$append_element'" + echo " Expected: '$expected_appended'" + echo " Got: '$appended'" + exit 1 + fi +} + +test_list_prepend_element() { + local test_string="apple:banana:cherry:date:grape" + local prepend_element="new_element" + local expected_prepended="new_element:apple:banana:cherry:date:grape" + list_prepend_element "$test_string" "$prepend_element" + local prepended=$_ret_ + if [[ "$prepended" != "$expected_prepended" ]]; then + echo "Prepend test failed:" + echo " Input list: '$test_string'" + echo " Prepend Element: '$prepend_element'" + echo " Expected: '$expected_prepended'" + echo " Got: '$prepended'" + exit 1 + fi +} + +test_list_find_element_regex() { + local test_string="apple:banana:cherry:date:grape" + + # Test element found + local regex="^banana$" + local expected_index=1 + list_find_element_regex "$test_string" "$regex" + local found_index=$_ret_ + if [[ "$found_index" -ne $expected_index ]]; then + echo "Find element regex test failed:" + echo " Input list: '$test_string'" + echo " Regex: '$regex'" + echo " Expected index: $expected_index" + echo " Got index: $found_index" + exit 1 + fi + + # Test element not found + local not_found_regex="^pear$" + local expected_not_found="-1" + list_find_element_regex "$test_string" "$not_found_regex" + local not_found_index=$_ret_ + if [[ "$not_found_index" != "$expected_not_found" ]]; then + echo "Find element regex test for not found failed:" + echo " Input list: '$test_string'" + echo " Regex: '$not_found_regex'" + echo " Expected index: $expected_not_found" + echo " Got index: $not_found_index" + exit 1 + fi +} + +# test_list_size +# test_list_insert_element +# test_list_remove_at +# test_list_find_element +# test_list_remove_element_if_exist +# test_list_remove_non_existent_element +# test_list_append_element +# test_list_prepend_element +# test_list_find_element_regex + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/cross_system_cp_with_rlink.bash b/linux_shell/build_script/base/cross_system_cp_with_rlink.bash new file mode 100644 index 0000000..eb45042 --- /dev/null +++ b/linux_shell/build_script/base/cross_system_cp_with_rlink.bash @@ -0,0 +1,141 @@ +#!/bin/bash +# shellcheck disable=SC2155 +# 已经过时 winrar本身就支持软链接的复制 + + + + +if ! type "include" >/dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}" + } +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then + return 0 +fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash +# C:\Users\wyc>mklink /? +# 创建符号链接。 +# +# MKLINK [[/D] | [/H] | [/J]] Link Target +# +# /D 创建目录符号链接。默认为文件符号链接。 +# /H 创建硬链接而非符号链接。 (硬链接本质上是:一个文件内容,对应多个文件名, 所以硬链接没有“谁是原件、谁是副本”这个区别) +# /J 创建目录联接。 +# Link 指定新的符号链接名称。 +# Target 指定新链接引用的路径 +# (相对或绝对)。 +# dir /al +# wyc@ubuntu:/$ ln --help +# 用法:ln [选项]... [-T] 目标 链接名 +#  或:ln [选项]... 目标 +#  或:ln [选项]... 目标... 目录 +#  或:ln [选项]... -t 目录 目标... +# 在第一种格式中,创建具有指定<链接名>且指向指定<目标>的链接。 +# 在第二种格式中,在当前目录创建指向<目标>位置的链接。 +# 在第三、四种格式中,在指定<目录>中创建指向指定<目标>的链接。 +# 默认创建硬链接,当使用--symbolic 时创建符号链接。 +# 默认情况下,创建每个目标时不应存在与新链接的名称相同的文件。 +# 创建硬链接时,每个指定的<目标>都必须存在。符号链接可以指向任意的位置; +# 当链接解析正常时,将其解析为一个相对于其父目录的相对链接。 +# +# 必选参数对长短选项同时适用。 +# --backup[=CONTROL] 为每个已存在的目标文件创建备份文件 +# -b 类似--backup,但不接受任何参数 +# -d, -F, --directory 允许超级用户尝试创建指向目录的硬链接 +# (注意:此操作可能因系统限制而失败) +# --logical 如目标为符号链接,本次创建链接时将其解引用 +# -n, --no-dereference 如果给定<链接名>是一个链接至某目录的符号链接, +# 将其作为普通文件处理 +# -P, --physical 创建直接指向符号链接文件的硬链接 +# -r, --relative 创建相对于链接位置的符号链接 +# -s, --symbolic 创建符号链接而非硬链接 +# -S, --suffix=后缀 自行指定备份文件的后缀 +# -t, --target-directory=目录 在指定<目录>中创建链接 +# -T, --no-target-directory 总是将给定的<链接名>当作普通文件 +# -v, --verbose 列出每个链接的文件名称 +# --help 显示此帮助信息并退出 +# --version 显示版本信息并退出 +# +# 备份文件的后缀为"~",除非以--suffix 选项或是 SIMPLE_BACKUP_SUFFIX +# 环境变量指定。版本控制的方式可通过--backup 选项或 VERSION_CONTROL 环境 +# 变量来选择。以下是可用的变量值: +# +# none, off 不进行备份(即使使用了--backup 选项) +# never 永远使用普通方式备份 +# +# 使用 -s 选项会忽略 -L 和 -P。 +# 否则当<目标>为一个符号链接(默认为 -P)时,会由最后一个指定的选项来控制行为。 +# +# GNU coreutils 在线帮助: +# 请向 报告 ln 的翻译错误 +# 完整文档请见: +# 或者在本地使用:info '(coreutils) ln invocation' + + +# TODO: 支持复杂的参数 还是通过全局变量来实现 +# TODO: 远程get_sysroot qt 构建重构 + +export glmf_include_dir_list +export glmf_exclude_dir_list + + +generate_link_meta_file() { + local source_dir="$1" + local dir_name parent_dir + dir_name="$(basename "$source_dir")" + parent_dir="$(dirname "$source_dir")" + local target_dir="${3:-${parent_dir}/${dir_name}_origin}" + local meta_file="${4:-${target_dir}_meta.txt}" + + + # cp不会保留硬链接关系,硬链接被当成真实文件拷贝,软链接仍然存在 + cp -r --no-preserve=mode "${source_dir}" "${target_dir}" + local rlink_type # file dir broken + local target_link # 软链接目标(可能仍然是软链接) + local under_source_dir # 0 在 source_dir 下 1 不在 + local abs_rlink # 0 绝对路径 1 相对路径 + local resolved # 链接到最后的真实文件或目录路径 + local dir # 原始软链接所在的目录 + local rel # 软链接相对于 source_dir的目录 + while IFS= read -r -d '' link; do + # 读取软链接目标 + rel=${link#"$source_dir"/} + rm "$target_dir/$rel" + target_link="$(readlink "$link")" + dir=${link%/*} + # 判断是否绝对路径 + if [[ "$target_link" == /* ]]; then + abs_rlink=0 + resolved="$target_link" + else + abs_rlink=1 + resolved="$dir/$target_link" + fi + resolved=$(realpath -m "$resolved") + # 判断是否存在 + if [[ ! -e "$resolved" ]]; then + rlink_type="broken" + elif [[ -d "$resolved" ]]; then + rlink_type="dir" + elif [[ -f "$resolved" ]]; then + rlink_type="file" + else + rlink_type="broken" + fi + # 判断是否是source_dir 或者在source_dir下 + case "$resolved" in "$source_dir" | "$source_dir"/*) + under_source_dir=0 + ;; + *) + under_source_dir=1 + ;; + esac + + + printf "%s|%s|%s|%s|%s" \ + "$rel" "$target_link" "$rlink_type" "$under_source_dir" "$abs_rlink" + done < <(find "$source_dir" -type l -print0) +} diff --git a/linux_shell/build_script/base/deploy.bash b/linux_shell/build_script/base/deploy.bash new file mode 100644 index 0000000..5ff759c --- /dev/null +++ b/linux_shell/build_script/base/deploy.bash @@ -0,0 +1,402 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash + + + + +mkdir_with_symlink() { + local dest_dir="$1" # 要处理的目标目录 + local install_root="$2" # 安装根目录 + is_absolute_directory "$dest_dir" || { + echo "mkdir_with_rlink dest_dir=${dest_dir}" + exit 1 + } + is_absolute_directory "$install_root" || { + echo "install_root=${install_root}" + exit 1 + } + local target="${install_root}${dest_dir}" + if is_absolute_directory "$target"; then + #echo "$target 文件夹已存在,取消mkdir_symlink!" + return 0 + fi + local current_path="" + local dir_parts=() + IFS='/' read -ra dir_parts <<<"$dest_dir" + dir_parts=("${dir_parts[@]:1}") #(因为根目录是空字符串) + local dir_name + for dir_name in "${dir_parts[@]}"; do + current_path="$current_path/$dir_name" + local target_dir_path="${install_root}${current_path}" + if [ -L "$current_path" ]; then + local extern_rlink_target_path=$(readlink -f "$current_path") + local rlink_path="${target_dir_path}" + local rlink_dir_path="$(dirname "${rlink_path}")" + local rlink_target_path="$install_root$extern_rlink_target_path" + if [ ! -L "$rlink_path" ] || [ "$(readlink -f "$rlink_path")" != "$rlink_path" ]; then + mkdir_with_symlink "$extern_rlink_target_path" "$install_root" + get_relative_path "$rlink_dir_path" "$rlink_target_path" + ln -sf "$_ret_" "$rlink_path" + [ -n "$_cur_log_path_" ] && echo "=======dir symlink======= ln -sf $_ret_ $rlink_path " >>"$_cur_log_path_" + fi + elif [ ! -e "$target_dir_path" ]; then + mkdir -p "$target_dir_path" + fi + done +} + +cp_with_symlink() { + local dest_file="$1" # 源文件路径 + local install_root="$2" + is_absolute_file "$dest_file" || { + echo "[cp_with_symlink error] dest_file=${dest_file} is not absolute file!" + exit 1 + } + is_absolute_directory "$install_root" || { + echo "[cp_with_symlink error] install_root=${install_root} is not absolute directory!" + exit 1 + } + local target="${install_root}${dest_file}" + if is_absolute_file "$target"; then + echo "$target 文件已存在,取消cp_symlink!" + return 0 + fi + local dest_dir + dest_dir=$(dirname "$dest_file") + mkdir_with_symlink "${dest_dir}" "$install_root" + + local ret + ret=$target + if [ -L "$dest_file" ]; then + local extern_rlink_path="$dest_file" + local extern_rlink_target_path=$(readlink -f "$dest_file") + cp_with_symlink "${extern_rlink_target_path}" "$install_root" + ret=$_ret_ + local rlink_target_path="${install_root}${extern_rlink_target_path}" + local rlink_path="${install_root}${extern_rlink_path}" + local rlink_path_dir="$(dirname ${rlink_target_path})" + get_relative_path "$rlink_path_dir" "$rlink_target_path" + ln -sf "$_ret_" "$rlink_path" + [ -n "$_cur_log_path_" ] && echo "=file_symlink= ln -sf $_ret_ $rlink_path " >>"$_cur_log_path_" + else + cp "${dest_file}" "${target}" + echo "cp ${dest_file} ==> ${target}" + fi + + _ret_=$ret + return 0 +} + +# $1 传入一个数组,用于拷贝他们的依赖 +# $2 拷贝依赖的根目录 +copy_dependencies() { + #local abs_exe_path=$(realpath "$1") + local install_root="$2" + declare -A path_seen + declare -A error_line_skipped + declare -A rely_dir + local ldd_log="${install_root}/deploy_ldd.txt" + local run_path_log="${install_root}/deploy_run_path.txt" + local illegal_line="${install_root}/illegal_line.txt" + extract_absolute_paths() { + rely_dir=() + local abs_exe_path="$1" + local lines + mapfile -t lines < <(ldd "$abs_exe_path") + local result=() + echo "abs_exe_path == $abs_exe_path" >>"${ldd_log}" + for line in "${lines[@]}"; do + echo "line == $line" >>"${ldd_log}" + if [[ -z "$line" ]]; then + continue + fi + if [[ "$line" =~ ^[[:space:]]*/lib64/ld-linux-x86-64 ]]; then + continue + fi + if [[ "$line" =~ ^[[:space:]]*linux-vdso.so ]]; then + continue + fi + if [[ "$line" =~ ^[[:space:]]*statically\ linked ]]; then + continue + fi + if [[ -n "${error_line_skipped[$line]}" ]]; then + continue + fi + local fields + IFS=' ' read -r -a fields <<<"$line" + local num_fields=${#fields[@]} + if [ "${num_fields}" != 4 ]; then + echo "${abs_exe_path} == ${line} 判断属性数量错误! num_fields == ${num_fields}" >>"$illegal_line" + error_line_skipped["$line"]=1 + continue + fi + if [[ "${fields[2]}" == "not" && "${fields[3]}" == "found" ]]; then + echo "严重错误! ${abs_exe_path} 找不到$abs_exe_path的依赖: ${line}" | tee -a "$illegal_line" + #read -n 1 # 等待用户按下一个键 + #exit 1 + fi + if [ "${fields[1]}" != "=>" ]; then + echo "${abs_exe_path} == 判断是否第二个是=> ${fields[1]} != '>'" >>"$illegal_line" + error_line_skipped["$line"]=1 # 记录已跳过的行 + continue + fi + if [[ "${fields[2]}" =~ ^/ ]]; then + local path_with_rlink="${fields[2]}" + local dir_path_with_rlink=$(dirname "${path_with_rlink}") + if [[ -z "${rely_dir["$dir_path_with_rlink"]}" ]]; then + rely_dir["$dir_path_with_rlink"]=1 + fi + if [[ -z "${path_seen[$path_with_rlink]}" ]]; then + result+=("${path_with_rlink}") + path_seen["$path_with_rlink"]=1 + fi + fi + done + local rely_dir_path + local runpath_list="" + declare -A seen_paths + for rely_dir_path in "${!rely_dir[@]}"; do + get_relative_origin_path "$(dirname "${abs_exe_path}")" "${rely_dir_path}" + path="${_ret_}" + if [[ -n "$path" && -z "${seen_paths[$path]}" ]]; then + seen_paths[$path]=1 + runpath_list+="${path}:" + fi + done + runpath_list="${runpath_list%:}" + if [[ "${runpath_list}" ]]; then + patchelf --set-rpath "${runpath_list}" "${install_root}${abs_exe_path}" + fi + echo "${abs_exe_path} == ${runpath_list} " >>"${run_path_log}" + _ret_="$( + IFS=: + echo "${result[*]}" + )" + } + _cp_rely() { + local abs_exe_path="$1" + local install_root="$2" + mkdir -p "${install_root}" + chmod 777 "${install_root}" + cp_with_symlink "${abs_exe_path}" "${install_root}" + extract_absolute_paths "${abs_exe_path}" + local tobe_install_list + local tobe_install + IFS=':' read -ra tobe_install_list <<<"$_ret_" + for tobe_install in "${tobe_install_list[@]}"; do + if [ -e "$tobe_install" ]; then + _cp_rely "$tobe_install" "$install_root" + fi + done + } + + _cur_log_path_="cp_reply_log.txt" + + paths=$1 + IFS=':' read -r -a path_array <<<"$paths" + for path in "${path_array[@]}"; do + local abs_exe_path + if [ -d "$path" ]; then + local executable_files=$(find "$path" -type f -executable) + while IFS= read -r abs_exe_path; do + _cp_rely "$abs_exe_path" "$install_root" + done <<<"$executable_files" + elif [ -f "$path" ]; then + abs_exe_path=$(realpath "$path") + _cp_rely "$abs_exe_path" "$install_root" + else + echo "ERROR WARING _cp_rely 路径无效或不存在: $path" >>"${_cur_log_path_}" + echo "ERROR WARING _cp_rely 路径无效或不存在: $path" + exit 1 + fi + done +} + +# 获取一个名称为了不重复 让目录尾数递加 +get_no_repeat_dir() { + local install_root="$1" + local original_install_root="$install_root" + local counter=1 + while [ -e "$install_root" ]; do + install_root="${original_install_root}_${counter}" # 在原目录名后加上数字 + ((counter++)) # 增加计数器 + done + _ret_="$install_root" +} + +copy_qt_plugin() { + local target_dir="$1" + local qt_plugin_dir="$2" + + # 设置默认的 Qt 插件目录 + local default_qt_plugin_dirs=( + "/home/env/Qt5.14.2/5.14.2/gcc_64/plugins" + "/usr/lib/x86_64-linux-gnu/qt5/plugins/" + "/usr/lib/qt/plugins/" + "/usr/local/Qt-*/plugins/" + ) + + # 如果没有提供 qt_plugin_dir,尝试使用默认目录 + if [ -z "$qt_plugin_dir" ]; then + for dir in "${default_qt_plugin_dirs[@]}"; do + # 使用通配符来查找可能的目录 + for plugin_dir in $dir; do + if [ -d "$plugin_dir" ]; then + qt_plugin_dir="$plugin_dir" + break 2 # 找到一个有效的目录,退出循环 + fi + done + done + fi + + # 检查最终选择的源目录是否存在 + if [ ! -d "$qt_plugin_dir" ]; then + echo "错误: 源目录 ${qt_plugin_dir} 不存在。" + return 1 + fi + + # 创建目标目录并复制插件 + mkdir -p "$target_dir" + cp -r "$qt_plugin_dir" "$target_dir/" + + echo "成功复制 Qt 插件到 ${target_dir}。" + return 0 +} + +# 第一个参数可执行文件或库绝对路径 +# 发布的目录绝对路径 (不一定是真实的 同名会把名+1) +deploy() { + local executable="$1" + get_no_repeat_dir "$2" + local install_root=${_ret_} + echo "deploy " + echo "executable $1" + echo "no_repeat install_root $install_root" + echo "install_root $2" + mkdir -p "$install_root" + chmod 777 "$install_root" + local extern_exe_path=$(realpath "${executable}") + local extern_exe_dir=$(dirname "${extern_exe_path}") + local exe_path="${install_root}${extern_exe_path}" + local exe_dir="${install_root}${extern_exe_dir}" + copy_dependencies "${extern_exe_path}" "${install_root}" + ln -sf ".$extern_exe_path" "$install_root/$(basename "$extern_exe_path")" + compress_directory_tar_gz "$install_root" "$(dirname "$2")" "$(basename "$2").tar.gz" +} + +# ln -sf /home/user/myapp/target_dir /home/user/myapp/my_link +# 思路把需要的库拷贝到 qt lib底下 然后建立软连接 +# /home/env/Qt5.14.2/5.14.2/gcc_64 +# bin doc include lib mkspecs phrasebooks plugins qml translations +deploy_qt() { + local executable="$1" + get_no_repeat_dir "$2" + local install_root=${_ret_} + local extern_qt_dir="$3" + local qt_plugin_dir="$4" + echo "deploy_qt " + echo "executable $executable" + echo "install_root $install_root" + echo "extern_qt_dir $extern_qt_dir" + echo "qt_plugin_dir $qt_plugin_dir" + mkdir -p "$install_root" + chmod 777 "$install_root" + local extern_exe_path=$(realpath "${executable}") + local extern_exe_dir=$(dirname "${extern_exe_path}") + local extern_qt_platform_dir="${qt_plugin_dir}/platforms" + local exe_path="${install_root}${extern_exe_path}" + local exe_dir="${install_root}${extern_exe_dir}" + local qt_dir="${install_root}${extern_qt_dir}" + local qt_platform_dir="${install_root}${extern_qt_platform_dir}" + + copy_dependencies "${executable}:${extern_qt_platform_dir}" "${install_root}" + ln -sf ".$extern_exe_path" "$install_root/$(basename "$extern_exe_path")" + get_relative_path "${extern_exe_dir}" "${extern_qt_platform_dir}" + ln -sf "${_ret_}" "${exe_dir}/platforms" + + + + local linker_path=$(which ldd) + + if [ -z "$linker_path" ]; then + echo "链接器路径未找到。" + exit 1 + else + echo "链接器路径 ${linker_path}" + fi + + # 使用 cp 拷贝链接器到目标目录 + cp_with_symlink "$linker_path" "${install_root}" + + + ln -sf ".$linker_path" "$install_root/$(basename "$linker_path")" + echo "链接器已拷贝到 ${install_root} 1111 ${_ret_}" + + + compress_directory_tar_gz "$install_root" "$(dirname "$2")" "$(basename "$2").tar.gz" +} + +# 此函数获取系统链接器配置文件里写的路径 +get_etc_ld_so_config_paths() { + local ld_paths=() + while read -r line; do + # 排除注释行 + if [[ -n "$line" && "$line" != \#* && -d "$line" ]]; then + ld_paths+=("$line") + fi + done < <(grep -v '^#' /etc/ld.so.conf) + local conf_file + for conf_file in /etc/ld.so.conf.d/*; do + while read -r line; do + if [[ -n "$line" && "$line" != \#* && -d "$line" ]]; then + ld_paths+=("$line") + fi + done < <(grep -v '^#' "$conf_file") + done + local combined_paths="" + for path in "${ld_paths[@]}"; do + combined_paths+="${path}:" + done + combined_paths="${combined_paths%:}" + + _ret_="$combined_paths" + echo "系统配置文件找库路径:$combined_paths" >>"${_cur_log_path_}" +} + +set_all_runpath() { + local dir="$1" # 根目录 + get_etc_ld_so_config_paths + list_append_element "$_ret_" "/lib64:/usr/lib64" + if [ -n "$LD_LIBRARY_PATH" ]; then + list_prepend_element "$_ret_" "$LD_LIBRARY_PATH" + fi + local base_path_list="$_ret_" + printf "set_all_runpath base_path_list== \n%s\n" "$base_path_list" | tr ':' '\n' + _set_all_runpath() { + local dir="$1" # 根目录 + local prefix="$2" # 当前深度 + prefix=${prefix:-"\$ORIGIN"} + list_prepend_all_element "$base_path_list" "$prefix" + local item + for item in "$dir"/*; do + if [ -d "$item" ]; then + _set_all_runpath "$item" "${prefix}/.." + elif [[ "$item" == *.so* ]]; then + $(echo "") + #patchelf --set-rpath "$_ret_" "$item" + fi + done + } + _set_all_runpath "$dir" +} + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/download_msys2.bash b/linux_shell/build_script/base/download_msys2.bash new file mode 100644 index 0000000..cfae9cd --- /dev/null +++ b/linux_shell/build_script/base/download_msys2.bash @@ -0,0 +1,78 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" >/dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}" + } +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash + +#download_msys2_pkg() { +# local repo="$1" +# local pkg_name="$2" +# local pkg_root="$3" +# local sha256="${4:-}" +# +# check_and_create_dir_var pkg_root +# +# local pkg_path="${pkg_root}/${pkg_name}" +# local url="https://mirror.msys2.org/mingw/${repo}/${pkg_name}" +# +# if [[ -f "${pkg_path}" ]]; then +# echo "[reuse] ${pkg_path}" >&2 +# else +# echo "[download] ${url}" >&2 +# curl -L --fail --retry 3 \ +# -o "${pkg_path}" \ +# "${url}" +# fi +# +# if [[ -n "${sha256}" ]]; then +# echo "${sha256} ${pkg_path}" | sha256sum -c - >&2 +# fi +# +# printf '%s\n' "${pkg_path}" +#} + +#download_msys2_pkg() { +# local repo="$1" +# local pkg_name="$2" +# local pkg_root="$3" +# local sha256="${4:-}" +# check_and_create_dir_var pkg_root >&2 +# local pkg_path="${pkg_root}/${pkg_name}" +# local url="https://mirror.msys2.org/mingw/${repo}/${pkg_name}" +# if [[ -f "${pkg_path}" ]]; then +# echo "[reuse] ${pkg_path}" >&2 +# else +# echo "[download] ${url}" >&2 +# curl -L --fail --retry 3 -o "${pkg_path}" "${url}" +# fi +# if [[ -n "${sha256}" ]]; then +# echo "${sha256} ${pkg_path}" | sha256sum -c - >&2 +# fi +# printf '%s\n' "${pkg_path}" +#} + +download_msys2_pkg() { + local -n out_path="$1" + local repo="$2" + local pkg_name="$3" + local pkg_root="$4" + local sha256="${5:-}" + check_and_create_dir_var pkg_root + out_path="${pkg_root}/${pkg_name}" + local url="https://mirror.msys2.org/mingw/${repo}/${pkg_name}" + if [[ -f "${out_path}" ]]; then + echo "[reuse] ${out_path}" >&2 + else + echo "[download] ${url}" >&2 + curl -L --fail --retry 3 -o "${out_path}" "${url}" + fi + if [[ -n "${sha256}" ]]; then + echo "${sha256} ${out_path}" | sha256sum -c - >&2 + fi +} diff --git a/linux_shell/build_script/base/export.bash b/linux_shell/build_script/base/export.bash new file mode 100644 index 0000000..7c7e15f --- /dev/null +++ b/linux_shell/build_script/base/export.bash @@ -0,0 +1,51 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash + +# shellcheck source=./cacl.bash +# shellcheck source=./check.bash +# shellcheck source=./common.bash +# shellcheck source=./compress.bash +# shellcheck source=./container.bash +# shellcheck source=./cross_system_cp_with_rlink.bash +# shellcheck source=./deploy.bash +# shellcheck source=./download_msys2.bash +# shellcheck source=./get_src.bash +# shellcheck source=./git.bash +# shellcheck source=./init_env.bash +# shellcheck source=./load_library.bash +# shellcheck source=./other.bash +# shellcheck source=./show.bash +# shellcheck source=./string.bash +# shellcheck source=./template.bash +# shellcheck source=./triplet.bash +# shellcheck source=./windows.bash + +include "${BASH_SOURCE[0]}" ./cacl.bash +include "${BASH_SOURCE[0]}" ./check.bash +include "${BASH_SOURCE[0]}" ./common.bash +include "${BASH_SOURCE[0]}" ./compress.bash +include "${BASH_SOURCE[0]}" ./container.bash +include "${BASH_SOURCE[0]}" ./cross_system_cp_with_rlink.bash +include "${BASH_SOURCE[0]}" ./deploy.bash +include "${BASH_SOURCE[0]}" ./download_msys2.bash +include "${BASH_SOURCE[0]}" ./get_src.bash +include "${BASH_SOURCE[0]}" ./git.bash +include "${BASH_SOURCE[0]}" ./init_env.bash +include "${BASH_SOURCE[0]}" ./load_library.bash +include "${BASH_SOURCE[0]}" ./other.bash +include "${BASH_SOURCE[0]}" ./show.bash +include "${BASH_SOURCE[0]}" ./string.bash +include "${BASH_SOURCE[0]}" ./template.bash +include "${BASH_SOURCE[0]}" ./triplet.bash +include "${BASH_SOURCE[0]}" ./windows.bash + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/get_src.bash b/linux_shell/build_script/base/get_src.bash new file mode 100644 index 0000000..6c144da --- /dev/null +++ b/linux_shell/build_script/base/get_src.bash @@ -0,0 +1,253 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash + + + + +# shellcheck source=./common.bash +# shellcheck source=./compress.bash +include "${BASH_SOURCE[0]}" ./common.bash +include "${BASH_SOURCE[0]}" ./compress.bash + + +download_cached_as() { + local url="$1" + local dest_dir="$2" + local filename="$3" + local cache_filepath="$4" + + # 参数检查 + if [[ -z "$url" || -z "$dest_dir" || -z "$filename" || -z "$cache_filepath" ]]; then + echo "[ERROR] 用法: download_cached_as " >&2 + return 1 + fi + + # 检查全局缓存目录变量 + if [[ -z "${_wget_cache_dir_}" ]]; then + echo "[ERROR] 全局缓存目录变量 _wget_cache_dir_ 未设置" >&2 + return 1 + fi + + # 创建目标目录 + mkdir -p "$dest_dir" || { + echo "[ERROR] 创建目标目录失败: $dest_dir" >&2 + return 1 + } + + # 创建缓存目录 + mkdir -p "$_wget_cache_dir_" || { + echo "[ERROR] 创建缓存目录失败: $_wget_cache_dir_" >&2 + return 1 + } + + # 目标文件路径 + local dest_file="${dest_dir%/}/$filename" + + # 缓存文件路径 + local cache_file="${_wget_cache_dir_%/}/$cache_filepath" + local cache_dir="$(dirname "$cache_file")" + check_and_create_dir "$cache_dir" + + # 如果目标文件已经存在,直接跳过 + if [[ -f "$dest_file" ]]; then + echo "[CACHE] 目标文件已存在,跳过: $dest_file" + return 0 + fi + + # 如果缓存文件不存在,则先下载到缓存目录 + if [[ ! -f "$cache_file" ]]; then + echo "[DOWNLOAD] $url" + echo "[CACHE TO] $cache_file" + + local tmp_cache_file="${cache_file}.tmp.$$" + + wget -O "$tmp_cache_file" "$url" + local rc=$? + + if [[ $rc -ne 0 ]]; then + echo "[ERROR] 下载失败: $url" >&2 + rm -f "$tmp_cache_file" + return $rc + fi + + mv -f "$tmp_cache_file" "$cache_file" || { + echo "[ERROR] 缓存文件写入失败: $cache_file" >&2 + rm -f "$tmp_cache_file" + return 1 + } + + echo "[OK] 已缓存: $cache_file" + else + echo "[CACHE] 命中缓存: $cache_file" + fi + + # 从缓存复制到目标位置 + cp -f "$cache_file" "$dest_file" || { + echo "[ERROR] 从缓存复制到目标失败: $cache_file -> $dest_file" >&2 + return 1 + } + + echo "[OK] 已复制到目标: $dest_file" + return 0 +} + + +get_src_from_wget(){ + if [ "$#" -ne 3 ]; then + echo "用法: get_src_from_wget " + echo " - 存储返回路径的变量名" + echo " - 解压到的目标目录,也是用于构建的目录" + echo " - 要下载的文件的URL" + echo "示例:" + echo ' src_dir=""' + echo ' get_src_from_wget src_dir $_build_dir $url' + return 1 + fi + + local -n ret=$1 + local dest_dir=$2 + local url=$3 + local suffix + get_suffix suffix "$url" + local file_name=$(basename "$url") + local name=$(basename "$url" .$suffix) + local zip_file_path="${_wget_cache_dir_}/$file_name" + ret="$dest_dir/$name" + if [ -d $ret ]; then + rm -rf $ret + fi + + if [ ! -e "$zip_file_path" ]; then + _network_status_=$? # 获取 wget 命令的返回值 + if [ $_network_status_ -ne 0 ]; then + # 如果 wget 命令失败,打印错误信息并要求用户手动下载 + echo "错误: 网络不通,放弃下载源码包,请手动下载源码包并放到以下路径:" + echo "路径: ${zip_file_path}" + echo "请下载源码包并将其放置在该目录下,然后重新运行脚本。" + exit 1 # 退出脚本 + fi + exec_record_fast_fail "wget -P ${_wget_cache_dir_} $url" + fi + +# if [ ! -e $zip_file_path ]; then +# exec_record "wget -P ${_wget_cache_dir_} $url" +# fi + exec_record_fast_fail "extract $suffix $zip_file_path $dest_dir" +} + + + + + + +configure_gnu_ex() { + if [ "$#" -lt 1 ]; then + echo "用法: configure_gnu_ex \"\"" + return 1 + fi + local src_dir="$1" + local opts="$2" + local build_dir="$src_dir/build" + exec_record "rm -rf \"${src_dir}/build\"" + exec_record "mkdir -p \"$build_dir\"" + exec_record "cd \"$build_dir\"" + local print_opts + print_opts="$(printf "%s" "$opts" | tr -s ' ' '\n')" + log_info "【$(pwd)/configure" + log_info "${print_opts}" + log_info "】" + exec_record_fast_fail "../configure ${opts}" + + + if [ $? -ne 0 ]; then + print_remain_args "src_dir:${src_dir} configure failed" "$opts" + exit 1 + fi +} + + + +configure_gnu() { + if [ "$#" -lt 1 ]; then + echo "用法: configure_gnu [additional configure options...]" + return 1 + fi + local src_dir="$1" + shift + local opts_string="$*" + configure_gnu_ex "$src_dir" "$opts_string" +} + + + +configure_gnu_zip_ex() { + # 参数检查 + if [ "$#" -lt 1 ]; then + echo "用法: configure_gnu_zip_ex \"\"" + echo " - 要下载并构建的源代码的 URL" + echo " - 传递给 configure 的额外参数(字符串)" + echo "示例:" + echo ' configure_gnu_zip_ex http://example.com/source.tar.gz "--prefix=/usr/local --enable-foo"' + return 1 + fi + local url="$1" + local opts="$2" + local src_dir="" + get_src_from_wget src_dir "${_build_dir_}" "$url" + log_info "$src_dir" "$opts" + configure_gnu_ex "$src_dir" "$opts" +} + +configure_gnu_zip() { + if [ "$#" -lt 1 ]; then + echo "用法: configure_gnu_zip [additional build options...]" + return 1 + fi + local url="$1" + shift + local opts_string="$*" + configure_gnu_zip_ex "$url" "$opts_string" +} + + + + + + + +build_gnu_zip_ex() { + if [ "$#" -lt 1 ]; then + echo "用法: build_gnu_zip_ex \"\"" + return 1 + fi + local url="$1" + local opts="$2" + configure_gnu_zip_ex "$url" "$opts" + exec_record_fast_fail "make -j $(nproc)" + exec_record_fast_fail "make install -j $(nproc)" +} + +build_gnu_zip() { + if [ "$#" -lt 1 ]; then + echo "用法: build_gnu_zip [opts...]" + return 1 + fi + local url="$1" + shift + local opts_string="$*" + build_gnu_zip_ex "$url" "$opts_string" +} + + + + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/git.bash b/linux_shell/build_script/base/git.bash new file mode 100644 index 0000000..514bd6a --- /dev/null +++ b/linux_shell/build_script/base/git.bash @@ -0,0 +1,371 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" >/dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}" + } +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash + +# 目前只是使用第一个url +get_git_urls() { + local dep="$1" + local -n out_urls="$2" + case "$dep" in + llvm) + out_urls=( + "https://github.com/llvm/llvm-project.git" + "https://gitee.com/mirrors/llvm-project.git" + ) + ;; + gmp) + out_urls=( + # 这个需要登陆?没法注册 + "https://gitlab.inria.fr/gmp/gmp.git" + ) + ;; + mpfr) + out_urls=( + "https://gitlab.inria.fr/mpfr/mpfr.git" + ) + ;; + mpc) + out_urls=( + "https://gitlab.inria.fr/mpc/mpc.git" + ) + ;; + llvm-project) + out_urls=( + "https://github.com/llvm/llvm-project" + "https://gitee.com/mirrors/llvm-project.git" + ) + ;; + linux) + out_urls=( + "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git" + "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git" + "https://mirrors.tuna.tsinghua.edu.cn/git/linux.git" + + ) + ;; + glibc) + out_urls=( + "https://sourceware.org/git/glibc.git" + "https://mirrors.tuna.tsinghua.edu.cn/git/glibc.git" + ) + ;; + newlib-cygwin) + out_urls=( + "https://github.com/mirror/newlib-cygwin.git" + ) + ;; + mingw-w64) + out_urls=( + "https://github.com/mingw-w64/mingw-w64.git" + "https://mirrors.tuna.tsinghua.edu.cn/git/mingw-w64.git" + "https://git.code.sf.net/p/mingw-w64/mingw-w64" + ) + ;; + zlib) + out_urls=( + "https://github.com/madler/zlib.git" + "https://gitee.com/mirrors/zlib.git" + ) + ;; + libxml2) + out_urls=( + "https://gitlab.gnome.org/GNOME/libxml2.git" + "https://gitee.com/mirrors/libxml2.git" + ) + ;; + musl) + out_urls=( + "https://git.musl-libc.org/git/musl" + ) + ;; + binutils-gdb) + out_urls=( + "https://sourceware.org/git/binutils-gdb.git" + "https://mirrors.tuna.tsinghua.edu.cn/git/binutils-gdb.git" + ) + ;; + gcc) + out_urls=( + "https://gcc.gnu.org/git/gcc.git" + "https://gitee.com/mirrors/gcc.git" + ) + ;; + windows-msvc-sysroot) + out_urls=( + "https://github.com/trcrsired/windows-msvc-sysroot.git" + ) + ;; + cppwinrt) + out_urls=( + "https://github.com/microsoft/cppwinrt.git" + "https://gitee.com/qabeowjbtkwb/cppwinrt.git" + ) + ;; + Qt) + out_urls=( + "https://github.com/qt/qt5.git" + ) + ;; + cpython) + out_urls=( + "https://github.com/python/cpython.git" + ) + ;; + cef) + out_urls=( + "https://github.com/chromiumembedded/cef.git" + ) + ;; + *) + log_error "未知依赖:${dep}" + return 1 + ;; + esac +} +get_repo_refs_local() { + local repo_dir="$1" + local -n out_branches="$2" + local -n out_tags="$3" + if [[ ! -d "${repo_dir}/.git" ]]; then + log_error "不是 git 仓库: ${repo_dir}" + return 1 + fi + pushd "$repo_dir" >/dev/null || return 1 + mapfile -t out_branches < <( + git branch --format='%(refname:short)' + ) + mapfile -t out_tags < <( + git tag --sort=-version:refname + ) + popd >/dev/null +} +get_repo_refs_remote() { + local repo_url="$1" + local -n out_branches="$2" + local -n out_tags="$3" + if [[ -z "$repo_url" ]]; then + log_error "repo_url 为空" + return 1 + fi + mapfile -t out_branches < <( + git ls-remote --heads "$repo_url" | + awk '{print $2}' | + sed 's#refs/heads/##' + ) + mapfile -t out_tags < <( + git ls-remote --tags "$repo_url" | + grep -v '\^{}' | + awk '{print $2}' | + sed 's#refs/tags/##' + ) +} +repo_has_ver_local() { + local repo_dir="$1" + local ver="$2" + + local branches=() + local tags=() + + get_repo_refs_local "$repo_dir" branches tags || return 1 + + for b in "${branches[@]}"; do + [[ "$b" == "$ver" ]] && return 0 + done + + for t in "${tags[@]}"; do + [[ "$t" == "$ver" ]] && return 0 + done + + return 1 +} +repo_has_ver_remote() { + local repo_url="$1" + local ver="$2" + + local branches=() + local tags=() + + get_repo_refs_remote "$repo_url" branches tags || return 1 + + for b in "${branches[@]}"; do + [[ "$b" == "$ver" ]] && return 0 + done + + for t in "${tags[@]}"; do + [[ "$t" == "$ver" ]] && return 0 + done + + return 1 +} +print_repo_refs_local() { + local repo_dir="${1:-.}" + log_info "========== 本地仓库信息 ==========" + log_info "路径: 【${repo_dir}】" + if [[ ! -d "${repo_dir}/.git" ]]; then + log_error "不是 git 仓库" + return 1 + fi + pushd "$repo_dir" >/dev/null || return 1 + log_info "\n当前 HEAD:" + git rev-parse --short HEAD + log_info "\n当前分支:" + git branch --show-current + popd >/dev/null + local branches=() + local tags=() + get_repo_refs_local "$repo_dir" branches tags + log_info "本地 Branch:" + printf '%s' "${branches[@]:0:20}" + log_info "Tag 列表:" + printf '%s' "${tags[@]:0:20}" + log_info "远端地址:" + git -C "$repo_dir" remote -v +} + +print_array_in_columns() { + local -n arr_ref="$1" + local cols="${2:-3}" + + if ((cols < 1)); then + cols=1 + fi + + local count="${#arr_ref[@]}" + if ((count == 0)); then + printf '无\n' + return 0 + fi + + local max_width=0 + local item + for item in "${arr_ref[@]}"; do + if ((${#item} > max_width)); then + max_width="${#item}" + fi + done + + local cell_width=$((max_width + 2)) + local rows=$(((count + cols - 1) / cols)) + local r c idx + + for ((r = 0; r < rows; r++)); do + for ((c = 0; c < cols; c++)); do + idx=$((c * rows + r)) + if ((idx < count)); then + printf "%-*s" "$cell_width" "${arr_ref[idx]}" + fi + done + printf '\n' + done +} + +print_repo_refs_remote() { + local repo_url="$1" + local cols="${2:-4}" + + log_info "========== 远端仓库信息 ==========" + log_info "URL: 【$repo_url】" + + local branches=() + local tags=() + + get_repo_refs_remote "$repo_url" branches tags || return 1 + + log_info "远端 Branch:" + print_array_in_columns branches "$cols" + + log_info "远端 Tag:" + print_array_in_columns tags "$cols" +} + +get_latest_git_tag() { + local repo_url="$1" + git ls-remote --tags "$repo_url" | + grep -v '\^{}' | + awk '{print $2}' | + sed 's#refs/tags/##' | + sort -V | + tail -n 1 +} +export use_network=1 +# ver 指的是 git 的 branch 或者 tag + +ensure_repo_version() { + local -n repo_dir=$1 + local dep="$2" + local ver="$3" + repo_dir="${_git_cache_dir_}/${dep}" + local urls=() + + log_info "ensure_repo_version ${dep} ${ver}" + get_git_urls "$dep" urls || return 1 + local repo_url="${urls[0]}" + # CHECK_REPO + + # CHECK_LOCAL + log_info "检查是否需要克隆" + if [[ ! -d "$repo_dir/.git" ]]; then + log_info "克隆仓库: $repo_url → $repo_dir" + if ! exec_record "git clone --origin origin \"$repo_url\" \"$repo_dir\" "; then + log_error "clone 失败" + return 1 + fi + fi + + # CHECK_LOCAL + log_info "测试本地是否有版本" + if repo_has_ver_local "$repo_dir" "$ver"; then + log_info "checkout $ver" + exec_record "git -C \"$repo_dir\" checkout \"$ver\" " || { + log_error "checkout 失败" + return 1 + } + return 0 + fi + + # FETCH + log_info "fetch 更新仓库" + if ! exec_record "git -C \"$repo_dir\" fetch --tags origin"; then + log_error "fetch 失败" + return 1 + fi + + if repo_has_ver_remote "$repo_dir" "${ver}"; then + : + else + log_error "远端仓库不存在版本: $ver" + print_repo_refs_remote "$repo_dir" + #exec_record " git ls-remote ${repo_url}" + return 3 + fi + + # CHECK_LOCAL AGAIN + if repo_has_ver_local "$repo_dir" "$ver"; then + log_info "checkout $ver" + + exec_record "git -C \"$repo_dir\" checkout \"$ver\" " || { + log_error "checkout 失败" + return 1 + } + return 0 + fi + + return 0 +} + +#configure_git_repo(){ +# local dep="$1" +# local ver="$2" +# local opts="$3" +# ensure_repo_version "${dep}" "${ver}" +# local repo_dir="${_git_cache_dir_}/${dep}" +# configure_gnu_ex "${repo_dir}" "$opts" +#} diff --git a/linux_shell/build_script/base/global_rely/export.bash b/linux_shell/build_script/base/global_rely/export.bash new file mode 100644 index 0000000..583c283 --- /dev/null +++ b/linux_shell/build_script/base/global_rely/export.bash @@ -0,0 +1,14 @@ +#!/bin/bash +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; + . ./log.bash + . ./stack_trace.bash +fi +include "${BASH_SOURCE[0]}" ./log.bash +include "${BASH_SOURCE[0]}" ./stack_trace.bash +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/global_rely/log.bash b/linux_shell/build_script/base/global_rely/log.bash new file mode 100644 index 0000000..fda80f1 --- /dev/null +++ b/linux_shell/build_script/base/global_rely/log.bash @@ -0,0 +1,158 @@ +#!/bin/bash +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi + +include "${BASH_SOURCE[0]}" ../../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; + source ../../pragma_once.bash +fi + + + + + +# 这个文件是构建的基础文件 存放最顶层的函数 +RESET='\033[0m' # 重置颜色 +BLACK='\033[0;30m' +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +WHITE='\033[0;37m' +BOLD_BLACK='\033[1;30m' +BOLD_RED='\033[1;31m' +BOLD_GREEN='\033[1;32m' +BOLD_YELLOW='\033[1;33m' +BOLD_BLUE='\033[1;34m' +BOLD_PURPLE='\033[1;35m' +BOLD_CYAN='\033[1;36m' +BOLD_WHITE='\033[1;37m' +export LOG_LEVEL="${LOG_LEVEL:-3}" # 0=ERROR 1=WARN 2=INFO 3=DEBUG 4=TRACE +export LOG_PATH="${LOG_PATH:-}" # 空则不写文件 +export LOG_STDOUT="${LOG_STDOUT:-1}" # 1 输出终端 +export LOG_COLOR_STDOUT="${LOG_COLOR_STDOUT:-1}" # 默认是否彩色 +export LOG_INIT_MODE="${LOG_INIT_MODE:-rotate}" # truncate|append|rotate +export LOG_INITIALIZED=0 + + +log_init() { + # 如果没有设置 LOG_PATH,直接返回 + [[ -z "$LOG_PATH" ]] && return 0 + + # 如果已经初始化过,直接返回 + (( LOG_INITIALIZED )) && return 0 + + # 获取日志文件的目录 + local log_dir + log_dir=$(dirname "$LOG_PATH") + + # 确保日志文件的目录存在,如果不存在则创建 + if [[ ! -d "$log_dir" ]]; then + mkdir -p "$log_dir" || { echo "ERROR: Failed to create log directory: $log_dir"; exit 1; } + fi + + # 确保日志文件存在,如果不存在则创建 + if [[ ! -f "$LOG_PATH" ]]; then + touch "$LOG_PATH" || { echo "ERROR: Failed to create log file: $LOG_PATH"; exit 1; } + chmod 777 $LOG_PATH + fi + + # 根据初始化模式进行操作 + case "$LOG_INIT_MODE" in + truncate) + : > "$LOG_PATH" # 清空日志文件 + ;; + append) + # 保持原样,直接追加 + ;; + rotate) + # 如果日志文件存在,重命名为带时间戳的文件 + if [[ -f "$LOG_PATH" ]]; then + mv "$LOG_PATH" "$LOG_PATH.$(date +%Y%m%d_%H%M%S)" + fi + ;; + *) + echo "Invalid LOG_INIT_MODE: $LOG_INIT_MODE" + exit 1 + ;; + esac + + # 标记为已初始化 + LOG_INITIALIZED=1 +} +log() { + + log_init + + local level_name="$1" + local level_num="$2" + local use_color="$3" + shift 3 + + (( level_num > LOG_LEVEL )) && return 0 + + local fmt="$1" + shift + + local body + + printf -v body -- "$fmt" "$@" + local timestamp + #timestamp="$(date '+%Y-%m-%d %H:%M:%S')" + + timestamp="$(TZ=Asia/Shanghai date '+%Y-%m-%d %H:%M:%S')" + + local msg + printf -v msg "[%s] [%s] %s" \ + "$timestamp" \ + "$level_name" \ + "$body" + + # -------- stdout -------- + if (( LOG_STDOUT )); then + + local enable_color + + if [[ -z "$use_color" ]]; then + enable_color="$LOG_COLOR_STDOUT" + else + enable_color="$use_color" + fi + + if (( enable_color )) && [[ -t 1 ]]; then + + local color="" + case "$level_name" in + ERROR) color="$BOLD_RED" ;; + WARN) color="$BOLD_YELLOW" ;; + INFO) color="$GREEN" ;; + DEBUG) color="$CYAN" ;; + TRACE) color="$PURPLE" ;; + *) color="$WHITE" ;; + esac + + printf "%b%s%b\n" "$color" "$msg" "$RESET" + else + printf "%s\n" "$msg" + fi + fi + + # -------- file -------- + if [[ -n "$LOG_PATH" ]]; then + printf "%s\n" "$msg" >> "$LOG_PATH" + fi +} + + +log_error() { log ERROR 0 1 "$@"; } +log_warn() { log WARN 1 1 "$@"; } +log_info() { log INFO 2 1 "$@"; } +log_debug() { log DEBUG 3 1 "$@"; } +log_trace() { log TRACE 4 1 "$@"; } + + diff --git a/linux_shell/build_script/base/global_rely/stack_trace.bash b/linux_shell/build_script/base/global_rely/stack_trace.bash new file mode 100644 index 0000000..0783b41 --- /dev/null +++ b/linux_shell/build_script/base/global_rely/stack_trace.bash @@ -0,0 +1,104 @@ +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../../pragma_once.bash + +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; + source ../../pragma_once.bash +fi + + +set -Eeo pipefail +# -e 命令失败退出 +# -E ERR trap 在函数中生效 +# -u 未定义变量报错 +# pipefail pipeline 失败传播 +#set -E + + + +# -E 的作用是:让 ERR trap 在函数、子 shell 等上下文中也会触发 + +declare -gi G_PRINT_STACK_TRACE_COUNT=0 + +print_stack_trace() { + + printf "\n\n" + local ret="${1}" + local reason="${2}" + + G_Root="D:/proj/plant_sun_cat/build_script" + + + local ts + ts="$(TZ=Asia/Shanghai date '+%Y-%m-%d %H:%M:%S.%3N')" + + local pid="$$" + local bashpid="${BASHPID:-}" + local ppid="${PPID:-}" + local pwd_now + pwd_now="$(pwd 2>/dev/null || echo '')" + + local script_name="${BASH_SOURCE[1]:-${BASH_SOURCE[0]}}" + local last_cmd="${BASH_COMMAND:-}" + + local root_dir="${_library_root_dir_:-}" + local g_root="D:/proj/plant_sun_cat/build_script" + + log_error "\n[#%d]【%s】ret=%d pid=%s bashpid=%s ppid=%s \npwd=%s \nscript=%s \ncmd=%s \nts=%s \nlibrary_root=%s" \ + "$G_PRINT_STACK_TRACE_COUNT" \ + "$reason" \ + "$ret" \ + "$pid" \ + "$bashpid" \ + "$ppid" \ + "$pwd_now" \ + "$script_name" \ + "$last_cmd" \ + "$ts" \ + "$root_dir" + ((G_PRINT_STACK_TRACE_COUNT++)) || true + + + + + local depth=${#FUNCNAME[@]} + + for ((i=0;i /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +include "${BASH_SOURCE[0]}" ./other.bash +# shellcheck source=./global_rely/export.bash +# shellcheck source=./other.bash + + +echo -e "============================ 开始加载环境 ============================ " +## 开启调试模式,打印执行的每一行命令 +#set -x +## 关闭调试模式 +#set +x + +_ret_="" +_root_="" +echo "OSTYPE:$OSTYPE" +if [[ "$OSTYPE" == "linux-gnu"* ]]; then + _root_="/ae/bash" +elif [[ "$OSTYPE" == "win32"* ]]; then + _root_="/d/ae/cached_external_library/bash" +elif [[ "$OSTYPE" == "cygwin"* ]]; then + _root_="/d/ae/cached_external_library/bash" +elif [[ "$OSTYPE" == "msys"* ]]; then + _root_="/d/ae/cached_external_library/bash" +else + echo "未知操作系统类型:$OSTYPE" + exit 1 +fi + +#_library_root_dir_="$(cd "$(dirname ${BASH_SOURCE[0]})" && pwd)/" +# 脚本在 library_root/base 下面所以往上找一层 +_library_root_dir_="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +_cur_log_path_="" +_install_="${_root_}/install" +_src_="${_root_}/src" +_build_="${_root_}/build" +_win_="${_root_}/win" +_iso_repo_="${_root_}/iso_repo" +_wget_cache_dir_="${_root_}/0_wget_cache_dir" +_git_cache_dir_="${_root_}/0_git_cache_dir" +_build_dir_="${_root_}/0_build_dir" +_network_status_="" + + + + +echo -e "[init global bash environment!]" +print_important_var _library_root_dir_ +print_important_var _cur_log_path_ +check_and_create_dir_var _root_ +check_and_create_dir_var _install_ +check_and_create_dir_var _src_ +check_and_create_dir_var _win_ +check_and_create_dir_var _iso_repo_ +check_and_create_dir_var _wget_cache_dir_ +check_and_create_dir_var _git_cache_dir_ +check_and_create_dir_var _build_dir_ + + + +echo -e "============================ 加载环境完成 ============================ " + + diff --git a/linux_shell/build_script/base/load_library.bash b/linux_shell/build_script/base/load_library.bash new file mode 100644 index 0000000..5e52891 --- /dev/null +++ b/linux_shell/build_script/base/load_library.bash @@ -0,0 +1,98 @@ +#!/bin/bash +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi + +include "${BASH_SOURCE[0]}" ../pragma_once.bash + + +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; + source ./../pragma_once.bash + source ./container.bash +fi + +include "${BASH_SOURCE[0]}" container.bash + + + + + +print_exports() { + echo "All exported environment variables:" + export -p # 使用 `export -p` 显示所有已导出的变量 +} + + + +load_library() { + local library_list_str=$1 + local previous_PATH=${PATH} + local previous_LD_LIBRARY_PATH=${LD_LIBRARY_PATH} + local library_path_list_str=$LD_LIBRARY_PATH + local bin_path_list_str=$PATH + local library_list library lib_name version + IFS=':' read -r -a library_list <<<"$library_list_str" + for library in "${library_list[@]}"; do + IFS='-' read -r lib_name version <<<"$library" # 分割库名和版本 + local library_path="${_install_}/${lib_name}/${version}" + if [ ! -d "$library_path" ]; then + library_path="${_install_}/${library}" # 尝试原始库路径 + fi + if [ ! -d "$library_path" ]; then + echo "load_library ${library_path} not exist!" + exit 1 + fi + local lib_dir bin_dir + for lib_dir in "lib64" "lib"; do + local cur_path="${library_path}/${lib_dir}" + if [ -d "${cur_path}" ]; then + list_remove_element_if_exist "${library_path_list_str}" "${cur_path}" + list_prepend_element "${_ret_}" "${cur_path}" + library_path_list_str="${_ret_}" + fi + done + for bin_dir in "bin" "libexec" "include"; do + local cur_path="${library_path}/${bin_dir}" + if [ -d "${cur_path}" ]; then + list_remove_element_if_exist "${bin_path_list_str}" "${cur_path}" + list_prepend_element "${_ret_}" "${cur_path}" + bin_path_list_str="${_ret_}" + fi + done + done + + export LD_LIBRARY_PATH="${library_path_list_str}" + export PATH="${bin_path_list_str}" + + echo -e "===============[start] load_library加载环境变量:===============" + echo -e "[ param ]: ${library_list_str}" + echo -e "[ old LD_LIBRARY_PATH ]:" + IFS=":" read -r -a paths <<<"$previous_LD_LIBRARY_PATH" + for path in "${paths[@]}"; do + echo " $path" + done + echo -e "[ old PATH ]:" + IFS=":" read -r -a paths <<<"$previous_PATH" + for path in "${paths[@]}"; do + echo " $path" + done + # echo -e "[LD_LIBRARY_PATH]: ${LD_LIBRARY_PATH}" + # echo -e "[PATH]: ${PATH}" + + echo -e "[ LD_LIBRARY_PATH ]:" + IFS=":" read -r -a paths <<<"$LD_LIBRARY_PATH" + for path in "${paths[@]}"; do + echo " $path" + done + echo -e "[ PATH ]:" + IFS=":" read -r -a paths <<<"$PATH" + for path in "${paths[@]}"; do + echo " $path" + done + echo -e "===============[ended] load_library加载环境变量:===============" +} + + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/other.bash b/linux_shell/build_script/base/other.bash new file mode 100644 index 0000000..2cacedb --- /dev/null +++ b/linux_shell/build_script/base/other.bash @@ -0,0 +1,856 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash + + + +# 这种是为了语法提示 +# shellcheck source=./global_rely/log.bash +# shellcheck source=./global_rely/stack_trace.bash + + +check_baidu_network() { + local baidu_domain="www.baidu.com" # 要检测的目标域名 + echo "正在检测是否能连接到 $baidu_domain..." + + # 使用 ping 命令检测是否能连接到 baidu.com + if ping -c 1 "$baidu_domain" > /dev/null 2>&1; then + echo "$baidu_domain 网络连接正常。" + return 0 # 连接正常 + else + echo "无法连接到 $baidu_domain,网络不可达。" + return 1 # 网络不可达 + fi +} + +# 用法: +# chromium_net_check_report # 检测一次并输出报告 +# chromium_net_check_report --wait # 循环等待,直到“任一方式可用”为止,并持续输出报告 +# chromium_net_check_report --wait 300 # 最多等待 300 秒 +# +# 报告包含: +# 1) DNS 解析是否成功 +# 2) ping(ICMP) 是否通(注意:TUN/代理下可能一直不通) +# 3) curl HTTPS HEAD 是否通(更贴近实际拉代码/访问网页) +# +chromium_net_check_report() { + local host="chromium.googlesource.com" + local wait_mode=0 + local timeout=0 + + if [[ "${1:-}" == "--wait" ]]; then + wait_mode=1 + timeout="${2:-0}" # 0 = 无限等 + fi + + # ping 参数兼容:Windows (MSYS/Git-Bash) 用 -n/-w(ms),Linux/macOS 用 -c/-W(s) + local ping_count_flag="-c" + local ping_timeout_flag="-W" + local ping_timeout_val="1" + case "$(uname -s 2>/dev/null | tr '[:upper:]' '[:lower:]')" in + mingw*|msys*|cygwin*) + ping_count_flag="-n" + ping_timeout_flag="-w" + ping_timeout_val="1000" # ms + ;; + esac + + _ts() { + date "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "" + } + + _dns_check() { + # 尽量不用 nslookup 输出噪音:只判断能不能解析出 IP + if command -v getent >/dev/null 2>&1; then + getent hosts "$host" >/dev/null 2>&1 + return $? + elif command -v nslookup >/dev/null 2>&1; then + nslookup "$host" >/dev/null 2>&1 + return $? + else + return 127 + fi + } + + _ping_check() { + ping "${ping_count_flag}" 1 "${ping_timeout_flag}" "${ping_timeout_val}" "$host" >/dev/null 2>&1 + return $? + } + + _curl_check() { + if ! command -v curl >/dev/null 2>&1; then + return 127 + fi + curl -fsSI --max-time 6 "https://${host}/" >/dev/null 2>&1 + return $? + } + + _one_report() { + local dns_rc ping_rc curl_rc + local dns_status ping_status curl_status + local hint=() + + dns_rc=0; ping_rc=0; curl_rc=0 + + _dns_check; dns_rc=$? + _ping_check; ping_rc=$? + _curl_check; curl_rc=$? + + case "$dns_rc" in + 0) dns_status="OK" ;; + 127) dns_status="N/A(no nslookup/getent)" ;; + *) dns_status="FAIL" ;; + esac + + case "$ping_rc" in + 0) ping_status="OK" ;; + *) ping_status="FAIL" ;; + esac + + case "$curl_rc" in + 0) curl_status="OK" ;; + 127) curl_status="N/A(no curl)" ;; + *) curl_status="FAIL" ;; + esac + + echo "==================== Chromium Network Report ====================" + echo "Time: $(_ts)" + echo "Host: ${host}" + echo "------------------------------------------------------------------" + echo "DNS : ${dns_status}" + echo "PING : ${ping_status}" + echo "CURL : ${curl_status} (HTTPS HEAD https://${host}/)" + echo "------------------------------------------------------------------" + + # 解释/建议(按组合给) + if [[ "$dns_rc" != 0 && "$dns_rc" != 127 ]]; then + hint+=("DNS 解析失败:检查系统 DNS/Clash DNS 设置,或是否被劫持/污染。") + fi + + if [[ "$curl_rc" == 0 ]]; then + hint+=("HTTPS 可访问:用于 gclient/git 拉取通常已经足够。") + else + if [[ "$curl_rc" == 127 ]]; then + hint+=("未检测到 curl:建议安装/启用 curl(Git-Bash 通常自带)。") + else + hint+=("HTTPS 不可访问:通常表示代理/TUN 未生效或证书/网络被拦。") + fi + fi + + if [[ "$ping_rc" != 0 ]]; then + hint+=("PING 不通:在 Clash TUN/代理下可能正常(ICMP 常被丢弃)。不要只以 ping 为唯一标准。") + fi + + if [[ "${#hint[@]}" -gt 0 ]]; then + echo "Notes:" + local i + for i in "${hint[@]}"; do + echo " - $i" + done + fi + + echo "==================================================================" + + # 返回码策略: + # 0 = curl OK(认为网络可用) + # 1 = curl FAIL(不可用) + if [[ "$curl_rc" == 0 ]]; then + return 0 + fi + return 1 + } + + if [[ "$wait_mode" -eq 0 ]]; then + _one_report + return $? + fi + + local start_ts now_ts elapsed + start_ts=$(date +%s 2>/dev/null || echo 0) + + echo "[WAIT] 循环检测中:直到 CURL 可访问为止(timeout=${timeout}s,0=无限)" + while true; do + if _one_report; then + echo "[DONE] CURL 已可访问:网络就绪" + return 0 + fi + + if [[ "$timeout" -gt 0 && "$start_ts" -ne 0 ]]; then + now_ts=$(date +%s 2>/dev/null || echo 0) + elapsed=$((now_ts - start_ts)) + if [[ "$elapsed" -ge "$timeout" ]]; then + echo "[TIMEOUT] 等待超过 ${timeout}s,仍不可访问 https://${host}/" + return 2 + fi + fi + + sleep 3 + done +} + + + + +print_important_var() { + local var=$1 # 传入的变量名 + local val=${!var} # 使用 eval 来获取变量的值 + echo "【${var}】=== 【${val}】" +} + + + + + + + +load_PATH(){ + local tmp + merge_args tmp ":" "$@" + export PATH="${tmp}${PATH:+:$PATH}" +} + +load_LIBRARY_PATH(){ + local tmp + merge_args tmp ":" "$@" + export LIBRARY_PATH="${tmp}${LIBRARY_PATH:+:$LIBRARY_PATH}" +} + +load_LD_LIBRARY_PATH(){ + local tmp + merge_args tmp ":" "$@" + export LD_LIBRARY_PATH="${tmp}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" +} + +load_ALL(){ + load_PATH "$@" + load_LIBRARY_PATH "$@" + load_LD_LIBRARY_PATH "$@" +} +save_env() { + export saved_PATH="$PATH" + export saved_LIBRARY_PATH="$LIBRARY_PATH" + export saved_LD_LIBRARY_PATH="$LD_LIBRARY_PATH" +} + +restore_env() { + export PATH="$saved_PATH" + export LIBRARY_PATH="$saved_LIBRARY_PATH" + export LD_LIBRARY_PATH="$saved_LD_LIBRARY_PATH" +} + +# 公用函数:打印指定环境变量的路径 +print_env_path() { + local env_var="$1" # 环境变量名 + local env_value="${!env_var}" # 获取环境变量的值 + # 输出环境变量的路径 + log_info "[ $env_var ]:" + IFS=":" read -r -a paths <<< "$env_value" + i=0 + for path in "${paths[@]}"; do + # 使用 printf 格式化 $i,确保它是 3 位,右对齐 + formatted_i=$(printf "%2d" "$i") + log_info "$formatted_i: $path" + ((i++)) || true + done +} + + +print_env() { + log_trace "========================== 【 打印环境变量 】 ==========================" + print_env_path "PATH" + print_env_path "LD_LIBRARY_PATH" + print_env_path "LD_RUN_PATH" + print_env_path "LIBRARY_PATH" + log_trace "========================== 【 打印环境变量 】 ==========================" +} + + +print_remain_args(){ + local err=$1 + shift 1 + local i=0 + log_error "msg:${err}" + for param in "$@"; do + log_error "[%2d] $param" $i + ((i++)) + done +} + + + + + +pragma_once() { + # 1. 转换为绝对路径以确保唯一性 + local abs_path + abs_path=$(realpath "$1" 2>/dev/null || echo "$1") + if [ ! -e "$abs_path" ]; then + log_info "错误: 文件 '$1' 不存在。" + exit 1 + fi + + # 2. 生成 Key(只保留字母数字,其他转下划线) + local key="key_$(echo "$abs_path" | sed 's/[^a-zA-Z0-9]/_/g')" + + # 3. 精确匹配检查 + # 我们在 map 的两端和 key 的两端都加上分隔符 | + if [[ "$loaded_scripts_map" == *"|$key|"* ]]; then + return 1 # 已经加载过了 + else + # 第一次加载,存入时带上分隔符 + # 如果 map 为空,初始化为 |key|;如果不为空,追加 key| + if [[ -z "$loaded_scripts_map" ]]; then + loaded_scripts_map="|$key|" + else + loaded_scripts_map="${loaded_scripts_map}${key}|" + fi + return 0 # 允许加载 + fi +} +# 使用方式 +# if pragma_once "${BASH_SOURCE[0]}"; then +# fi + + + + + +centos7_6_init_iso_root() { + sudo yum --disablerepo=* --enablerepo=wyc groupinstall "Development Tools" -y + sudo yum --disablerepo=* --enablerepo=wyc install gmp-devel mpfr-devel libmpc-devel openssl mesa-libGL-devel -y +} + + +check_directory() { + local dir="$1" + if [ ! -d "$dir" ]; then + echo "错误: 目录不存在: $dir" + return 1 + fi + return 0 +} + +check_directory_var() { + local var_name="$1" + local dir="${!var_name}" + + if [ -z "$var_name" ]; then + echo "错误: 未传入变量名" + return 1 + fi + + if [ -z "$dir" ]; then + echo "错误: 变量未定义或为空: $var_name" + return 1 + fi + + if [ ! -d "$dir" ]; then + echo "错误: 目录不存在: $var_name=$dir" + return 1 + fi + + return 0 +} + + + +check_file() { + local file="$1" + if [ ! -f "$file" ]; then + echo "错误: 文件不存在: $file" + return 1 + fi + return 0 +} + +check_file_ex() { + local prefix="$1" + local file="$2" + if [ ! -f "$file" ]; then + echo "【${prefix}】 错误: 文件不存在: $file" + return 1 + fi + return 0 +} + +check_file_var() { + local var_name="$1" + local file="${!var_name}" + + if [ -z "$var_name" ]; then + echo "错误: 未传入变量名" + return 1 + fi + + if [ -z "$file" ]; then + echo "错误: 变量未定义或为空: $var_name" + return 1 + fi + + if [ ! -f "$file" ]; then + echo "错误: 文件不存在: $var_name=$file" + return 1 + fi + + return 0 +} + +is_absolute_directory() { + local dir_path="$1" + if [[ "$dir_path" != /* ]] || [ ! -d "$dir_path" ]; then + return 1 + fi + return 0 +} + +is_absolute_file() { + local file_path="$1" + if [[ "$file_path" != /* ]] || [ ! -f "$file_path" ]; then + return 1 + fi + return 0 +} + +is_absolute_elf() { + local path="$1" + if [[ "$path" != /* ]]; then + echo "Not an absolute path: $path" + return 1 + fi + if [[ ! -f "$path" ]]; then + echo "File not found: $path" + return 1 + fi + if ! file "$path" | grep -q 'ELF'; then + echo "Not an ELF file: $path" + return 1 + fi + return 0 +} + +is_valid_absolute_path_format() { + local input="$1" + if [[ "$input" =~ ^(/[^:/]+)+(:/[^:/]+)+$ ]]; then + return 1 + fi + echo "Invalid format: $input" + return 0 +} + +#!/bin/bash + +# 压缩函数:将目录压缩为 .tar.gz 格式 +compress_directory_tar_gz() { + local source_dir="$1" # 源目录 + local install_root="$2" # 目标目录 + local archive_name="$3" # 压缩包名称 + if [ ! -d "$source_dir" ]; then + echo "compress_directory Error: Source directory '$source_dir' does not exist!" + return 1 + fi + echo "Compressing '$source_dir' to '$install_root/$archive_name'..." + # 去除硬链接 +# local workdir="$(dirname "$source_dir")" +# local a2="$(basename "$source_dir")" + tar --hard-dereference -czvf "$install_root/$archive_name" -C "${source_dir}" . + + if [ $? -eq 0 ]; then + echo "Compression successful! $install_root/$archive_name" + else + echo "Compression failed! $install_root/$archive_name" + return 1 + fi +} + + +compress_directory_tar_gz() { + local source_dir="$1" # 源目录 + local install_root="$2" # 目标目录 + local archive_name="$3" # 压缩包名称 + if [ ! -d "$source_dir" ]; then + echo "compress_directory Error: Source directory '$source_dir' does not exist!" + return 1 + fi + echo "Compressing '$source_dir' to '$install_root/$archive_name'..." + # 去除硬链接 +# local workdir="$(dirname "$source_dir")" +# local a2="$(basename "$source_dir")" + tar --hard-dereference -czvf "$install_root/$archive_name" -C "${source_dir}" . + + if [ $? -eq 0 ]; then + echo "Compression successful! $install_root/$archive_name" + else + echo "Compression failed! $install_root/$archive_name" + return 1 + fi +} + +# 解压函数:将 .tar.gz 文件解压到目标目录 +compress_directory_tar_gz_copy() { + local source_dir="$1" + local install_root="$2" + local archive_name="$3" + + if [ ! -d "$source_dir" ]; then + echo "compress_directory Error: Source directory '$source_dir' does not exist!" + return 1 + fi + + echo "Compressing '$source_dir' to '$install_root/$archive_name'..." + + tar --dereference --hard-dereference -czvf "$install_root/$archive_name" -C "${source_dir}" . + + if [ $? -eq 0 ]; then + echo "Compression successful! $install_root/$archive_name" + else + echo "Compression failed! $install_root/$archive_name" + return 1 + fi +} + +# 示例用法 +# compress_directory "/path/to/source_directory" "/path/to/your/install_root" "your_archive_name.tar.gz" +# decompress_archive "/path/to/your/install_root/your_archive_name.tar.gz" "/path/to/target_directory" + + +# 通用检查函数:检查值是否在给定范围内 +check_value_in_range() { + local param_name="$1" # 参数名称 + shift # 移除参数名称,剩下的是有效范围 + + # 获取参数的当前值 + local value="${!param_name}" + + # 遍历所有范围值 + for range_value in "$@"; do + if [[ "$value" == "$range_value" ]]; then + return 0 # 找到匹配的值,返回成功 + fi + done + + # 如果没有找到匹配值,打印错误并退出 + log_error "ERROR: '$param_name' has invalid value '$value'. Valid values are: $*" + exit 77 +} + +check_ret_exit() { + local ret=$? + local msg="$1" + + if (( ret != 0 )); then + if [[ -z "${msg//[[:space:]]/}" ]]; then + msg="命令执行失败" + fi + log_error "${msg} ret=${ret}" + exit "$ret" + fi +} + + +clear_dir_contents() { + local dir="$1" + + # 参数为空时直接报错返回 + if [[ -z "$dir" ]]; then + echo "[ERROR] clear_dir_contents: 目录参数不能为空" >&2 + return 1 + fi + + # 目录不存在时跳过,不报错 + if [[ ! -d "$dir" ]]; then + echo "[INFO] 目录不存在,跳过清空: $dir" + return 0 + fi + + # 删除普通文件和普通目录 + rm -rf "${dir:?}/"* + + # 删除隐藏文件/目录(例如 .git、.cache),但不匹配 . 和 .. + rm -rf "${dir:?}/".[!.]* + + # 删除以两个点开头的隐藏文件/目录,但仍然不会匹配 .. 本身 + rm -rf "${dir:?}/"..?* + + echo "[OK] 已清空目录内容: $dir" +} + +check_and_create_dir_var() { + local dir_var=$1 # 传入的变量名 + local dir_path=${!dir_var} # 使用 eval 来获取变量的值 + + # 检查目录是否存在 + if [ -d "$dir_path" ]; then + echo "【${dir_var}】: 【$dir_path】" + : + else + # 如果目录不存在,则尝试创建目录 + echo "【${dir_var}】目录不存在,正在创建: $dir_path" + mkdir -p "$dir_path" # 创建目录,-p 确保父目录也被创建 + if [ $? -ne 0 ]; then + echo "【${dir_var}】错误: 创建目录失败 $dir_path" + exit 1 # 返回失败代码 + else + echo "【${dir_var}】目录创建成功: $dir_path" + fi + fi +} + +check_and_create_dir() { + local dir="$1" + # 非空判断:空字符串或全空白都算空 + if [[ -z "${dir//[[:space:]]/}" ]]; then + log_error "ERROR: dir is empty" + exit 4 + fi + + if [[ ! -d "$dir" ]]; then + log_info "Attempting to create the directory... 【${dir}】" + mkdir -p "$dir" + if [[ $? -ne 0 ]]; then + log_error "ERROR: Failed to create directory 【${dir}】" + exit 5 + fi + chmod 777 "$dir" + if [[ $? -ne 0 ]]; then + log_error "ERROR: Failed to chmod 777 【${dir}】" + exit 6 + fi + fi +} + + + +# 使用示例 +# declare -a files +# regex_glob_files files "/ae/bash/0_git_cache_dir/binutils-gdb" "/ae/bash/0_git_cache_dir/binutils-gdb/build" '.*\.(c|h)$' +# echo "count: ${#files[@]}" +# printf '%s\n' "${files[@]}" +# i=0 +# for f in "${files[@]}"; do +# printf '%d: %s\n' "$i" "$f" +# ((i++)) +# done + +regex_glob_files() { + if [ $# -lt 4 ]; then + return 1 + fi + + local ret_name="$1" + local include_path="$2" + local exclude_path="$3" + local regex_expr="$4" + + if [ -z "$ret_name" ]; then + return 1 + fi + + local -n ret="$ret_name" + ret=() + + if [ -z "$include_path" ] || [ ! -e "$include_path" ]; then + return 0 + fi + + local include_abs="" + local exclude_abs="" + local item="" + local base_name="" + + include_abs=$(realpath "$include_path") + + if [ -n "$exclude_path" ] && [ -e "$exclude_path" ]; then + exclude_abs=$(realpath "$exclude_path") + fi + + if [ -f "$include_abs" ]; then + if [ -n "$exclude_abs" ] && [ "$include_abs" = "$exclude_abs" ]; then + return 0 + fi + + if [ -n "$regex_expr" ]; then + base_name="${include_abs##*/}" + if [[ "$base_name" =~ $regex_expr ]]; then + ret+=("$include_abs") + fi + else + ret+=("$include_abs") + fi + + return 0 + fi + + if [ -d "$include_abs" ]; then + while IFS= read -r item; do + if [ -n "$regex_expr" ]; then + base_name="${item##*/}" + if [[ "$base_name" =~ $regex_expr ]]; then + ret+=("$item") + fi + else + ret+=("$item") + fi + done < <( + if [ -n "$exclude_abs" ]; then + find "$include_abs" \ + \( -path "$exclude_abs" -o -path "$exclude_abs/*" \) -prune -o \ + -type f -print + else + find "$include_abs" -type f -print + fi + ) + + return 0 + fi + + return 0 +} + + +# * 任意长度任意字符(可为0) *.c a.c, test.c a.cpp +# ? 任意1个字符 a?.txt ab.txt a.txt, abc.txt +# [abc] 匹配集合中一个字符 file[12].txt file1.txt file3.txt +# [a-z] 匹配范围内一个字符 file[a-z].txt filea.txt fileA.txt +# [!abc] 不在集合中的一个字符 file[!0-9].txt filea.txt file1.txt +glob_files_by_name() { + if [ $# -lt 4 ]; then + return 1 + fi + + local ret_name="$1" + local include_path="$2" + local exclude_path="$3" + local name_pattern="$4" + + local -n ret="$ret_name" + ret=() + + [ -z "$include_path" ] && return 0 + [ ! -e "$include_path" ] && return 0 + + local include_abs + local exclude_abs="" + + include_abs=$(realpath "$include_path") + + if [ -n "$exclude_path" ] && [ -e "$exclude_path" ]; then + exclude_abs=$(realpath "$exclude_path") + fi + + if [ -f "$include_abs" ]; then + local base_name="${include_abs##*/}" + if [[ "$base_name" == $name_pattern ]]; then + ret+=("$include_abs") + fi + return 0 + fi + + while IFS= read -r item; do + ret+=("$item") + done < <( + if [ -n "$exclude_abs" ]; then + find "$include_abs" \ + \( -path "$exclude_abs" -o -path "$exclude_abs/*" \) -prune -o \ + -type f -name "$name_pattern" -print + else + find "$include_abs" -type f -name "$name_pattern" -print + fi + ) +} + +# 生成命令行脚本 给某些makefile使用 + +_generate_case_dispatch_script_begin() { + if [ $# -ne 1 ]; then + return 1 + fi + + local ret_name="$1" + local -n ret="$ret_name" + + ret="" + ret+=$'#!/usr/bin/env bash\n' + ret+=$'set -euo pipefail\n' + ret+=$'\n' + ret+=$'case "${2:-${1:-}}" in\n' +} + +_generate_case_dispatch_script_append_case() { + if [ $# -ne 3 ]; then + return 1 + fi + + local ret_name="$1" + local case_label="$2" + local case_value="$3" + + if [ -z "$case_label" ] || [ -z "$case_value" ]; then + return 1 + fi + + local -n ret="$ret_name" + + ret+="${case_label})"$'\n' + printf -v ret '%s printf '\''%%s'\\\\n\'' "%s"\n' "$ret" "$case_value" + ret+=$' ;;\n' +} + +_generate_case_dispatch_script_end() { + if [ $# -ne 1 ]; then + return 1 + fi + + local ret_name="$1" + local -n ret="$ret_name" + + ret+=$'*)\n' + ret+=$' echo "unsupported args: $*" >&2\n' + ret+=$' exit 1\n' + ret+=$' ;;\n' + ret+=$'esac\n' + ret+=$'exit 0\n' +} + +generate_case_dispatch_script_string() { + if [ $# -lt 3 ]; then + return 1 + fi + + local ret_name="$1" + shift + + if [ -z "$ret_name" ]; then + return 1 + fi + + if [ $(( $# % 2 )) -ne 0 ]; then + return 1 + fi + + _generate_case_dispatch_script_begin "$ret_name" || return 1 + + local case_label="" + local case_value="" + + while [ $# -gt 0 ]; do + case_label="$1" + case_value="$2" + shift 2 + _generate_case_dispatch_script_append_case "$ret_name" "$case_label" "$case_value" || return 1 + done + + _generate_case_dispatch_script_end "$ret_name" || return 1 + return 0 +} + + + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/show.bash b/linux_shell/build_script/base/show.bash new file mode 100644 index 0000000..cf80944 --- /dev/null +++ b/linux_shell/build_script/base/show.bash @@ -0,0 +1,43 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash + +# 遍历当前目录下的所有文件 +check_rpath_runpath() { + local dir="$1" + # 遍历当前目录下的所有文件 + find "$dir" -type f -executable | while read -r file; do + # 检查是否为可执行文件且不是目录 + if [[ -x "$file" && ! -d "$file" ]]; then + echo "File: $file" + # 查看 RPATH + rpath=$(readelf -d "$file" | grep -E 'RPATH') + runpath=$(readelf -d "$file" | grep -E 'RUNPATH') + # 打印结果 + if [ -n "$rpath" ]; then + echo " RPATH: $rpath" + else + echo " RPATH: Not set" + fi + if [ -n "$runpath" ]; then + echo " RUNPATH: $runpath" + else + echo " RUNPATH: Not set" + fi + echo "" + fi + done +} +# 调用函数 +#check_rpath_runpath "/ae/bbb" +#check_rpath_runpath "./" + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/string.bash b/linux_shell/build_script/base/string.bash new file mode 100644 index 0000000..cfcbd38 --- /dev/null +++ b/linux_shell/build_script/base/string.bash @@ -0,0 +1,104 @@ +#!/bin/bash +# shellcheck disable=SC2155 +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +# shellcheck source=./global_rely/export.bash + + + +get_relative_path_ex() { + local abs_path=${1%/} + local abs_rely_path=${2%/} + local base=$3 + local abs_path_array + local abs_rely_path_array + if [[ "$abs_path" == "$abs_rely_path" ]]; then + if [[ -n "$base" ]]; then + _ret_="${base}" + else + _ret_="./" + fi + return 0 + fi + IFS='/' read -r -a abs_path_array <<<"$abs_path" + IFS='/' read -r -a abs_rely_path_array <<<"$abs_rely_path" + local abs_path_length=${#abs_path_array[@]} + local abs_rely_path_length=${#abs_rely_path_array[@]} + local i=0 + while [[ "${abs_path_array[i]}" == "${abs_rely_path_array[i]}" ]]; do + ((i++)) + done + local result="" + for ((j = i; j < abs_path_length; j++)); do + result="../$result" + done + if [[ -n "$base" ]]; then + result="${base}/$result" + fi + for ((j = i; j < abs_rely_path_length; j++)); do + result+="${abs_rely_path_array[j]}/" + done + _ret_="${result%/}" +} +get_relative_origin_path() { + get_relative_path_ex $1 $2 "\$ORIGIN" +} + +get_relative_path() { + get_relative_path_ex $1 $2 "" +} + + + +test_get_relative_path() { + # Array of test cases with each element containing: + # 1. Function name to call (either "get_relative_path" or "get_relative_path_ex") + # 2. First path argument + # 3. Second path argument + # 4. Base argument (for get_relative_path_ex, otherwise empty) + # 5. Expected result + local test_cases=( + # Format: "function_name path1 path2 base expected" + "get_relative_origin_path /home/user/project/folder /home/user/project/folder \$ORIGIN" + "get_relative_origin_path /home/user/project/folder /home/user/project \$ORIGIN/.." + "get_relative_origin_path /home/user/project/folder /home/user/tt/aa \$ORIGIN/../../tt/aa" + "get_relative_origin_path /home/user/project/folder/subfolder /home/user/project/another_folder \$ORIGIN/../../another_folder" + "get_relative_origin_path /var/www/html /home/user/tt/aa \$ORIGIN/../../../home/user/tt/aa" + + # Test cases with an empty base for get_relative_path_ex + "get_relative_path /home/user/project/folder /home/user/project/folder ./" + "get_relative_path /home/user/project/folder /home/user/project .." + "get_relative_path /home/user/project/folder /home/user/tt/aa ../../tt/aa" + "get_relative_path /home/user/project/folder/subfolder /home/user/project/another_folder ../../another_folder" + "get_relative_path /var/www/html /home/user/tt/aa ../../../home/user/tt/aa" + ) + + # Loop through each test case + for test_case in "${test_cases[@]}"; do + # Read the elements of the test case into variables + local function_name path1 path2 expected + IFS=" " read -r function_name path1 path2 expected <<<"$test_case" + # Call the appropriate function based on the test case + if [[ "$function_name" == "get_relative_origin_path" ]]; then + get_relative_origin_path "$path1" "$path2" + elif [[ "$function_name" == "get_relative_path" ]]; then + get_relative_path "$path1" "$path2" + fi + # Check the result + if [[ "$_ret_" != "$expected" ]]; then + echo "$function_name Test Failed:" + echo " Input: $path1, $path2" + echo " Expected: '$expected', but got '$_ret_'" + else + echo "$function_name Test Passed." + fi + done +} + +return 0 \ No newline at end of file diff --git a/linux_shell/build_script/base/sysroot.md b/linux_shell/build_script/base/sysroot.md new file mode 100644 index 0000000..492fbc7 --- /dev/null +++ b/linux_shell/build_script/base/sysroot.md @@ -0,0 +1,539 @@ +可以。你现在踩到的不是单个 `libc6` 问题,而是 **Debian/Ubuntu 发行版安装系统时自动维护了一整套隐式约定**。你自己做精简 sysroot 时,这些隐式行为都要手动还原,否则 GCC/ld/CMake 会报各种“明明有文件但找不到”的错误。 + +下面一次说完整。 + +--- + +# 1. 发行版真正安装包时做了什么 + +Ubuntu 不是简单把 `.deb` 文件解压到 `/`。正常 `apt install` / `dpkg -i` 会做这些事: + +| 行为 | 说明 | 你用 `dpkg-deb -x` 是否会做 | +| --------------------- | --------------------------------------------------- | --------------------- | +| 解包文件 | 把 deb 里的文件释放到根目录 | 会 | +| 解析依赖 | 自动安装 `Depends` 包 | 不会 | +| 执行 `preinst/postinst` | 包安装前后脚本 | 不会 | +| 执行 trigger | 例如 `ldconfig`、icon cache、man-db | 不会 | +| 维护 dpkg 数据库 | `/var/lib/dpkg/status` | 不会 | +| 创建/更新 alternatives | 例如 `/usr/bin/cc` 指向 gcc | 不会 | +| 保持 symlink 布局 | `/lib`、`/bin`、`libc.so.6` 等软链接 | 只解包原样;跨 Windows 打包可能丢 | +| 维护动态库缓存 | `/etc/ld.so.cache` | 不会 | +| 按 multiarch 放路径 | `/usr/lib/x86_64-linux-gnu`、`/lib/x86_64-linux-gnu` | 文件本身会解包,但你裁剪时可能漏 | + +所以 `dpkg-deb -x` 只是: + +```bash +把 deb 里的文件倒出来 +``` + +不是: + +```bash +完整安装一个 Ubuntu 包 +``` + +--- + +# 2. sysroot 里必须同时有“运行库”和“开发文件” + +你现在做 GCC/CMake 编译 sysroot,至少要分清这几类包。 + +## 2.1 `libc6` + +提供 glibc 运行库,通常包含: + +```text +/lib/x86_64-linux-gnu/libc.so.6 +/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 +/lib/x86_64-linux-gnu/libm.so.6 +/lib/x86_64-linux-gnu/libpthread.so.0 +/lib/x86_64-linux-gnu/libdl.so.2 +/lib/x86_64-linux-gnu/librt.so.1 +``` + +这些是运行期 ELF 文件。 + +你的错误: + +```text +cannot find /lib/x86_64-linux-gnu/libc.so.6 inside sysroot +cannot find /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 inside sysroot +``` + +就是缺这类文件,或者这些文件在错误位置。 + +## 2.2 `libc6-dev` + +提供 glibc 编译开发文件,通常包含: + +```text +/usr/include/stdio.h +/usr/include/features.h +/usr/lib/x86_64-linux-gnu/crt1.o +/usr/lib/x86_64-linux-gnu/crti.o +/usr/lib/x86_64-linux-gnu/crtn.o +/usr/lib/x86_64-linux-gnu/Scrt1.o +/usr/lib/x86_64-linux-gnu/rcrt1.o +/usr/lib/x86_64-linux-gnu/libc.so +/usr/lib/x86_64-linux-gnu/libc_nonshared.a +``` + +注意: + +```text +/usr/lib/x86_64-linux-gnu/libc.so +``` + +通常不是 ELF 动态库,而是 **ld linker script**。 + +里面会写类似: + +```text +GROUP ( + /lib/x86_64-linux-gnu/libc.so.6 + /usr/lib/x86_64-linux-gnu/libc_nonshared.a + AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) +) +``` + +所以即使你有: + +```text +/usr/lib/x86_64-linux-gnu/libc.so.6 +``` + +也不够。因为 `libc.so` 脚本明确让链接器去找: + +```text +/lib/x86_64-linux-gnu/libc.so.6 +/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 +``` + +## 2.3 `linux-libc-dev` + +提供 Linux UAPI headers: + +```text +/usr/include/linux/*.h +/usr/include/asm-generic/*.h +/usr/include/x86_64-linux-gnu/asm/*.h +``` + +这个是编译很多 Linux 程序需要的头文件,不提供 glibc runtime。 + +--- + +# 3. `/usr/lib` 和 `/lib` 不是可以随便互换的 + +你截图里有: + +```text +sysroot/usr/lib/x86_64-linux-gnu/libc.so.6 +``` + +但链接器要的是: + +```text +sysroot/lib/x86_64-linux-gnu/libc.so.6 +``` + +这是两个路径。 + +在真实 Ubuntu 系统里,发行版可能通过以下方式保证它们都正常: + +```text +/lib 是真实目录 +或者 /lib -> usr/lib +或者包里带了软链接 +或者 loader/linker script 指向固定路径 +``` + +但你自己裁剪 sysroot、再打包到 Windows 时,最容易丢的是: + +```text +/lib +/lib64 +软链接 +绝对 symlink +``` + +尤其 WinRAR 会提示“跳过可能不安全的链接”,这就会破坏 Linux sysroot。 + +--- + +# 4. `/lib64` 也可能必须存在 + +x86_64 glibc 的动态加载器有时通过这些路径出现: + +```text +/lib64/ld-linux-x86-64.so.2 +/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 +``` + +具体看你的: + +```bash +cat "$sysroot/usr/lib/x86_64-linux-gnu/libc.so" +``` + +只要 `libc.so` 里写了某个绝对路径,例如: + +```text +/lib64/ld-linux-x86-64.so.2 +``` + +那么 sysroot 里就必须有: + +```text +$sysroot/lib64/ld-linux-x86-64.so.2 +``` + +只要它写的是: + +```text +/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 +``` + +那么 sysroot 里就必须有: + +```text +$sysroot/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 +``` + +**规则很简单:linker script 里的绝对路径 `/xxx`,ld 使用 `--sysroot` 后会找 `$sysroot/xxx`。** + +--- + +# 5. `/usr/lib/x86_64-linux-gnu/libc.so` 是关键 + +你不要只看有没有 `libc.so.6`。真正要看这个: + +```bash +cat "$sysroot/usr/lib/x86_64-linux-gnu/libc.so" +``` + +然后把里面所有 `/lib/...`、`/usr/lib/...`、`/lib64/...` 的绝对路径都补齐。 + +可以用这个检查: + +```bash +target=x86_64-linux-gnu +sysroot=/ae/sysroots/ubuntu2004 + +echo "[INFO] libc.so linker script:" +cat "$sysroot/usr/lib/$target/libc.so" + +echo "[INFO] Absolute paths referenced by libc.so:" +grep -oE '/(lib64|lib|usr/lib)[^ )]+' "$sysroot/usr/lib/$target/libc.so" | sort -u + +echo "[INFO] Check referenced files:" +grep -oE '/(lib64|lib|usr/lib)[^ )]+' "$sysroot/usr/lib/$target/libc.so" | sort -u | while read -r p; do + if [ -e "$sysroot$p" ]; then + echo "[OK] $sysroot$p" + else + echo "[MISS] $sysroot$p" + fi +done +``` + +这个比猜测更可靠。 + +--- + +# 6. 你这种精简 sysroot 必须手动还原的东西 + +最终 sysroot 至少应该有: + +```text +usr/include/stdio.h +usr/include/features.h + +usr/include/linux +usr/include/asm-generic +usr/include/x86_64-linux-gnu/asm + +usr/lib/x86_64-linux-gnu/crt1.o +usr/lib/x86_64-linux-gnu/crti.o +usr/lib/x86_64-linux-gnu/crtn.o +usr/lib/x86_64-linux-gnu/Scrt1.o +usr/lib/x86_64-linux-gnu/rcrt1.o +usr/lib/x86_64-linux-gnu/libc.so +usr/lib/x86_64-linux-gnu/libc_nonshared.a + +lib/x86_64-linux-gnu/libc.so.6 +lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 + +lib64/ld-linux-x86-64.so.2 # 如果 libc.so 或工具链需要 +``` + +另外常见还需要: + +```text +lib/x86_64-linux-gnu/libm.so.6 +lib/x86_64-linux-gnu/libpthread.so.0 +lib/x86_64-linux-gnu/libdl.so.2 +lib/x86_64-linux-gnu/librt.so.1 +lib/x86_64-linux-gnu/libresolv.so.2 +lib/x86_64-linux-gnu/libgcc_s.so.1 +``` + +但 `libgcc_s.so.1` 最好来自你的 GCC 工具链,不要混旧系统版本,除非你明确知道搜索顺序。 + +--- + +# 7. 你之前的 rsync 白名单还要注意 symlink + +你的白名单应该保留: + +```bash +--include='/lib/' +--include="/lib/${target}/***" +--include='/lib64/***' +--include='/usr/' +--include='/usr/include/***' +--include='/usr/lib/' +--include="/usr/lib/${target}/***" +--include='/usr/lib/gcc/' +--include="/usr/lib/gcc/${target}/***" +--exclude='*' +``` + +但问题是:如果 `/lib` 是 symlink,或者里面的 `libc.so.6` 是 symlink,Windows 打包时可能丢。 + +所以给 Windows 工具链发布用,建议最后做一次“实体化”: + +```bash +sudo cp -aL "$src" "$dst" +``` + +`-L` 的意义是:如果源文件是软链接,就复制软链接指向的真实文件。 + +--- + +# 8. `cc` 也是发行版隐式行为 + +你前面遇到的 `cc 9.4` 也是同一类问题。 + +Ubuntu 发行版通常提供: + +```text +/usr/bin/cc -> /etc/alternatives/cc -> /usr/bin/gcc +``` + +但你自己 `make install` GCC 时,通常只生成: + +```text +gcc +g++ +c++ +cpp +``` + +不一定生成: + +```text +cc +``` + +所以如果 configure 里传了: + +```text +CC=cc +``` + +而你的工具链目录没有 `cc`,shell 就会继续往 PATH 后面找,最后找到系统 `/usr/bin/cc`。 + +这也是发行版帮你做了 `update-alternatives`,你自己的工具链没有。 + +--- + +# 9. `dpkg-deb -x` 方式的正确认知 + +你现在这种函数: + +```bash +install_iso_deb_to_sysroot_by_name "libc6-dev" ... +``` + +本质是: + +```text +从 ISO pool 找 deb -> 解包文件 -> 放入 sysroot +``` + +它不会自动安装依赖。 + +所以如果你解 `libc6-dev`,它可能依赖: + +```text +libc6 +linux-libc-dev +``` + +但它不会帮你自动解这两个包。 + +而 Live ISO 的 `/pool` 里不一定有 `libc6`,因为 `libc6` 已经在: + +```text +casper/filesystem.squashfs +``` + +里面了。 + +所以正确策略是: + +```text +libc6:优先从已解出的 rootfs 复制/修正 +libc6-dev:从 ISO pool 解包 +linux-libc-dev:从 ISO pool 解包 +``` + +--- + +# 10. 你应该采用的最终流程 + +## 第一步:unsquashfs 提取完整 rootfs + +```bash +sudo unsquashfs -d /ae/sysroots/ubuntu2004 /media/wyc/Ubuntu\ 20.04.6\ LTS\ amd64/casper/filesystem.squashfs +``` + +这个里面通常已经有: + +```text +/lib/x86_64-linux-gnu/libc.so.6 +/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 +``` + +## 第二步:从 ISO pool 解包开发包 + +```bash +libc6-dev +linux-libc-dev +``` + +## 第三步:生成精简 sysroot + +只复制这些: + +```text +/usr/include +/usr/lib/x86_64-linux-gnu +/lib/x86_64-linux-gnu +/lib64 +/etc/ld.so.conf +/etc/ld.so.conf.d +``` + +## 第四步:修正 glibc runtime 绝对路径 + +检查: + +```bash +cat "$sysroot/usr/lib/x86_64-linux-gnu/libc.so" +``` + +凡是里面写的绝对路径,必须在: + +```text +$sysroot + 绝对路径 +``` + +存在。 + +## 第五步:Windows 打包前实体化 symlink + +尤其是: + +```text +libc.so.6 +ld-linux-x86-64.so.2 +libm.so.6 +libpthread.so.0 +libdl.so.2 +librt.so.1 +libresolv.so.2 +``` + +不要让 WinRAR 跳过软链接。 + +--- + +# 11. 最终检查命令 + +在 Linux 打包前,对最终 sysroot 跑: + +```bash +target=x86_64-linux-gnu +sysroot=/path/to/final/sysroot + +check() { + if [ -e "$sysroot/$1" ]; then + echo "[OK] $1" + else + echo "[MISS] $1" + fi +} + +check "usr/include/stdio.h" +check "usr/include/features.h" + +check "usr/lib/$target/crt1.o" +check "usr/lib/$target/crti.o" +check "usr/lib/$target/crtn.o" +check "usr/lib/$target/Scrt1.o" +check "usr/lib/$target/libc.so" +check "usr/lib/$target/libc_nonshared.a" + +check "lib/$target/libc.so.6" +check "lib/$target/ld-linux-x86-64.so.2" + +if [ -e "$sysroot/usr/lib/$target/libc.so" ]; then + echo "[INFO] Checking absolute references in libc.so:" + grep -oE '/(lib64|lib|usr/lib)[^ )]+' "$sysroot/usr/lib/$target/libc.so" | sort -u | while read -r p; do + if [ -e "$sysroot$p" ]; then + echo "[OK] $p" + else + echo "[MISS] $p" + fi + done +fi +``` + +这个检查能直接解释你 CMake 那种错误。 + +--- + +# 12. 一句话总结 + +发行版隐式帮你维护了: + +```text +依赖关系 +multiarch 路径 +/lib 与 /usr/lib 布局 +/lib64 loader +glibc linker script 引用路径 +软链接 +cc alternatives +ldconfig/triggers +``` + +你现在不是在“正常安装 Ubuntu”,而是在做一个 **可发布到 Windows 的精简 Linux sysroot**。因此必须自己保证: + +```text +linker script 里引用的绝对路径,在 sysroot 里真实存在 +``` + +尤其是: + +```text +sysroot/lib/x86_64-linux-gnu/libc.so.6 +sysroot/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 +``` + +不能只看: + +```text +sysroot/usr/lib/x86_64-linux-gnu/libc.so.6 +``` diff --git a/linux_shell/build_script/base/template.bash b/linux_shell/build_script/base/template.bash new file mode 100644 index 0000000..44b1603 --- /dev/null +++ b/linux_shell/build_script/base/template.bash @@ -0,0 +1,231 @@ + +if ! type "include" > /dev/null 2>&1; then + include() { + . "$(cd "$(dirname "$1")" && pwd)/${2}"; + }; +fi +include "${BASH_SOURCE[0]}" ../pragma_once.bash +if ! pragma_once ${BASH_SOURCE[0]}; then return 0; fi +include "${BASH_SOURCE[0]}" ./global_rely/export.bash +include "${BASH_SOURCE[0]}" ./other.bash +# shellcheck source=./global_rely/export.bash +# shellcheck source=./other.bash + + + +# ========================= +# template.bash +# 纯 Bash 模板渲染 +# 占位符格式: {{KEY}} +# ========================= + +# 判断某个 key 是否合法 +_template_validate_key() { + local key="$1" + [[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] +} + +# 转义 replacement,避免 sed 替换时特殊字符出问题 +_template_escape_replacement() { + local s="$1" + s="${s//\\/\\\\}" + s="${s//&/\\&}" + s="${s//|/\\|}" + printf '%s' "$s" +} + +# 核心:对一个字符串做渲染 +# 用法: +# template_render_string "hello {{NAME}}" NAME "wyc" AGE "18" +template_render_string() { + if [ $# -lt 1 ]; then + echo "template_render_string: missing template string" >&2 + return 1 + fi + + local template_str="$1" + shift + + if [ $(( $# % 2 )) -ne 0 ]; then + echo "template_render_string: key/value arguments must be paired" >&2 + return 1 + fi + + local rendered="$template_str" + local key="" + local value="" + local escaped_value="" + + while [ $# -gt 0 ]; do + key="$1" + value="$2" + shift 2 + + if ! _template_validate_key "$key"; then + echo "template_render_string: invalid key: $key" >&2 + return 1 + fi + + escaped_value="$(_template_escape_replacement "$value")" + rendered="$(printf '%s' "$rendered" | sed "s|{{${key}}}|${escaped_value}|g")" + done + + printf '%s' "$rendered" +} + +# 从模板文件渲染到 stdout +# 用法: +# template_render_file /tmp/a.tpl NAME "wyc" AGE "18" +template_render_file() { + if [ $# -lt 1 ]; then + echo "template_render_file: missing template file" >&2 + return 1 + fi + + local template_file="$1" + shift + + if [ ! -f "$template_file" ]; then + echo "template_render_file: template file not found: $template_file" >&2 + return 1 + fi + + local content="" + content="$(cat "$template_file")" || return 1 + template_render_string "$content" "$@" +} + +# 从模板文件渲染到目标文件 +# 用法: +# template_render_to_file /tmp/a.tpl /tmp/out.conf NAME "wyc" +template_render_to_file() { + if [ $# -lt 2 ]; then + echo "template_render_to_file: usage: template_render_to_file