{"id":380,"date":"2024-06-06T13:44:10","date_gmt":"2024-06-06T05:44:10","guid":{"rendered":"https:\/\/blog.laning.org\/?p=380"},"modified":"2024-06-06T13:45:50","modified_gmt":"2024-06-06T05:45:50","slug":"armbian-build%e8%84%9a%e6%9c%ac%e5%88%86%e6%9e%90","status":"publish","type":"post","link":"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/","title":{"rendered":"Armbian\/build\u811a\u672c\u5206\u6790"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">1. \u811a\u672c\u76ee\u5f55\u68c0\u6d4b\u548c\u4ee3\u7801\u5065\u58ee\u6027\u4fdd\u8bc1<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1.1 \u7a0b\u5e8f\u62a5\u9519\u9000\u51fa\u811a\u672c<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>#set -o pipefail  # trace ERR through pipes - will be enabled \"soon\"\n#set -o nounset   ## set -u : exit the script if you try to use an uninitialised variable - one day will be enabled\nset -e\nset -o errtrace # trace ERR through - enabled\nset -o errexit  ## set -e : exit the script if any statement returns a non-true return value - enabled\n# Important, go read http:\/\/mywiki.wooledge.org\/BashFAQ\/105 NOW!<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">1.2. .\/compile.sh\u811a\u672c\u76ee\u5f55\u68c0\u6d4b<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>SRC=\"$(dirname \"$(realpath \"${BASH_SOURCE&#91;0]}\")\")\"\ncd \"${SRC}\" || exit\n\n# check for whitespace in ${SRC} and exit for safety reasons\ngrep -q \"&#91;&#91;:space:]]\" &lt;&lt;&lt; \"${SRC}\" &amp;&amp; {\n\techo \"\\\"${SRC}\\\" contains whitespace. Not supported. Aborting.\" >&amp;2\n\texit 1\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">2. single.sh \u6587\u4ef6\u52a0\u8f7d\uff08\u4f4d\u4e8e.\/lib\uff09<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">2.1 \u68c0\u67e5bash\u7248\u672c\u662f\u5426\u9ad8\u4e8e5.x<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># The Armbian functions require Bash 5.x.\nif &#91;&#91; \"${BASH_VERSINFO:-0}\" -lt 5 ]]; then\n\techo \"Armbian build scripts require Bash 5.x. Go get it...\" >&amp;2\n\tif &#91;&#91; \"${OSTYPE}\" == \"darwin\"* ]]; then\n\t\techo \"Armbian build scripts require brew to be installed and working on macOS. (old Bash version)\" >&amp;2\n\t\techo \"Please install brew, *restart your terminal*.\" >&amp;2\n\t\techo \"Then run 'brew install bash coreutils git', *restart your terminal* and then try again.\" >&amp;2\n\t\texit 51\n\tfi\n\texit 50\nfi<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2.2 macOS\u7cfb\u7edf\u68c0\u67e5<\/h3>\n\n\n\n<ul>\n<li>\u662f\u5426\u4ee5root\u8fd0\u884c\u811a\u672c<\/li>\n\n\n\n<li>Homebrew \u5305\u7ba1\u7406\u5668\u5df2\u5b89\u88c5\u5e76\u6b63\u5e38\u5de5\u4f5c<\/li>\n\n\n\n<li>\u901a\u8fc7 Homebrew \u7684 <code>coreutils<\/code> \u5b89\u88c5\u7684 <code>realpath<\/code> \u547d\u4ee4\u662f\u5426\u53ef\u7528<\/li>\n\n\n\n<li>\u66f4\u65b0 <code>PATH<\/code> \u73af\u5883\u53d8\u91cf\u4ee5\u5305\u542b\u7531 Homebrew \u5b89\u88c5\u7684 GNU <code>coreutils<\/code> \u4e8c\u8fdb\u5236\u6587\u4ef6\u3002<\/li>\n\n\n\n<li>\u786e\u4fdd <code>${SRC}<\/code> \u53d8\u91cf\uff08\u5e94\u6307\u5411\u6784\u5efa\u811a\u672c\u7684\u6e90\u76ee\u5f55\uff09\u4f4d\u4e8e\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u4e2d\u3002\u8fd9\u5bf9\u4e8e macOS \u4e0a\u7684 Docker \u517c\u5bb9\u6027\u5f88\u91cd\u8981\u3002<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code># If under Darwin, we require brew to be installed and working. Check.\nif &#91;&#91; \"${OSTYPE}\" == \"darwin\"* ]]; then\n\t# Don't allow running as root on macOS.\n\tif &#91;&#91; \"${EUID}\" -eq 0 ]]; then\n\t\techo \"Armbian build scripts do not support running as root on macOS.\" >&amp;2\n\t\techo \"Please run as a normal user.\" >&amp;2\n\t\texit 51\n\tfi\n\n\tif ! command -v brew &amp;> \/dev\/null; then\n\t\techo \"Armbian build scripts require brew to be installed and working on macOS. (brew not available)\" >&amp;2\n\t\techo \"Please install brew, *restart your terminal*.\" >&amp;2\n\t\techo \"Then run 'brew install bash coreutils git', *restart your terminal* and then try again.\" >&amp;2\n\t\texit 51\n\tfi\n\n\t# Run \"brew --prefix\" to check if brew is working.\n\tif ! brew --prefix &amp;> \/dev\/null; then\n\t\techo \"Armbian build scripts require brew to be installed and working on macOS. (brew --prefix failed)\" >&amp;2\n\t\techo \"Please install brew, *restart your terminal*.\" >&amp;2\n\t\techo \"Then run 'brew install bash coreutils git', *restart your terminal* and then try again.\" >&amp;2\n\t\texit 51\n\tfi\n\n\tdeclare brew_prefix\n\tbrew_prefix=\"$(brew --prefix)\"\n\n\t# Make sure realpath is available via brew's coreutils, under ${brew_prefix}\n\tif ! command -v \"${brew_prefix}\/opt\/coreutils\/libexec\/gnubin\/realpath\" &amp;> \/dev\/null; then\n\t\techo \"Armbian build scripts require realpath to be installed via brew's coreutils on macOS. (realpath not available)\" >&amp;2\n\t\techo \"Please install brew, *restart your terminal*.\" >&amp;2\n\t\techo \"Then run 'brew install bash coreutils git', *restart your terminal* and then try again.\" >&amp;2\n\t\techo \"If that fails, try 'brew reinstall bash coreutils git' and try again.\" >&amp;2\n\t\texit 51\n\tfi\n\n\t# If under Darwin, we need to set the PATH to include the GNU coreutils.\n\t# export PATH with new coreutils gnubin's in front.\n\texport PATH=\"${brew_prefix}\/opt\/coreutils\/libexec\/gnubin:$PATH\"\n\tunset brew_prefix\n\n\t# Under Darwin\/Docker, the \"${SRC}\" should be under \"${HOME}\" -- otherwise Docker will not be able to share\/mount it.\n\t# This is a sanity check to make sure that the user is not trying to build outside of \"${HOME}\".\n\tif &#91;&#91; \"${SRC}\" != \"${HOME}\"* ]]; then\n\t\techo \"Armbian build scripts require the Armbian directory ($SRC) to be under your home directory ($HOME) on macOS.\" >&amp;2\n\t\techo \"Please clone inside your home directory and try again.\" >&amp;2\n\t\texit 52\n\tfi\nfi<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2.3 \u68c0\u67e5realpath\u547d\u4ee4\u662f\u5426\u5b58\u5728<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>if &#91;&#91; -z \"$(command -v realpath)\" ]]; then\n\techo \"Armbian build scripts require coreutils. Go install it.\" >&amp;2\n\texit 53\nfi<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2.4 \u9632\u6b62\u7528\u6237\u76f4\u63a5\u8fd0\u884c <code>single.sh<\/code>,\u4f7f\u7528 <code>compile.sh<\/code> \u6765\u542f\u52a8\u6784\u5efa\u8fc7\u7a0b\u3002<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>if &#91;&#91; $(basename \"$0\") == single.sh ]]; then\n\techo \"Please use compile.sh to start the build process\"\n\texit 255\nfi<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2.5 \u901a\u8fc7<code>.\/lib\/library-functions.sh<\/code>\u6587\u4ef6\u52a0\u8f7dlib\u91cc\u9762\u7684\u51fd\u6570\u811a\u672c<\/h3>\n\n\n\n<p><a href=\"https:\/\/github.com\/armbian\/build\/blob\/main\/lib\/library-functions.sh\">build\/lib\/library-functions.sh at main \u00b7 armbian\/build \u00b7 GitHub<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. logging_init\u51fd\u6570\uff08\u4f4d\u4e8e.\/lib\/functions\/logging\/logging.sh\uff09<\/h2>\n\n\n\n<p>\u8fd9\u4e2a\u51fd\u6570\u8bbe\u7f6e\u4e86\u65e5\u5fd7\u663e\u793a\u7684\u9ed8\u8ba4\u884c\u4e3a\uff0c\u5305\u62ec\u662f\u5426\u5728\u7ec8\u7aef\u4e0a\u663e\u793a\u65e5\u5fd7\u3001\u662f\u5426\u542f\u7528\u8c03\u8bd5\u6a21\u5f0f\u7b49\u3002\u5b83\u8fd8\u6839\u636e\u7ec8\u7aef\u7684\u80cc\u666f\u8272\u8c03\u6574\u65e5\u5fd7\u989c\u8272\uff0c\u4ee5\u63d0\u9ad8\u53ef\u8bfb\u6027\uff0c\u5e76\u6839\u636e\u8fd0\u884c\u73af\u5883\uff08\u5982 CI\/CD \u7cfb\u7edf\u3001Docker \u5bb9\u5668\u3001WSL2 \u6216 macOS\uff09\u8c03\u6574\u65e5\u5fd7\u524d\u7f00\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># initialize logging variables. (this does not consider parameters at this point, only environment variables)\nlogging_init<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">4. traps_init\u51fd\u6570\uff08\u4f4d\u4e8e.\/lib\/functions\/logging\/traps.sh\uff09<\/h2>\n\n\n\n<p>\u521d\u59cb\u5316\u4e00\u7cfb\u5217\u7684\u4fe1\u53f7\u6355\u6349\uff08traps\uff09\uff0c\u4ee5\u4fbf\u5728\u811a\u672c\u6267\u884c\u8fc7\u7a0b\u4e2d\u6355\u6349\u5230\u7279\u5b9a\u7684\u4fe1\u53f7\uff08\u5982\u9519\u8bef\u3001\u9000\u51fa\u3001\u4e2d\u65ad\u548c\u7ec8\u6b62\u4fe1\u53f7\uff09\u65f6\u80fd\u591f\u6267\u884c\u76f8\u5e94\u7684\u5904\u7406\u51fd\u6570 <code>main_trap_handler<\/code><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function traps_init() {\n\t# shellcheck disable=SC2034 # Array of cleanup handlers.\n\tdeclare -g -a trap_manager_cleanup_handlers=()\n\t# shellcheck disable=SC2034 # Global to avoid doubly reporting ERR\/EXIT pairs.\n\tdeclare -g -i trap_manager_error_handled=0\n\ttrap 'main_trap_handler \"ERR\" \"$?\"' ERR\n\ttrap 'main_trap_handler \"EXIT\" \"$?\"' EXIT\n\ttrap 'main_trap_handler \"INT\" \"$?\"' INT\n\ttrap 'main_trap_handler \"TERM\" \"$?\"' TERM\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">5. \u786e\u4fdd\u76ee\u5f55\u5b89\u5168<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code># make sure git considers our build system dir as a safe dir (only if actually building)\n&#91;&#91; \"${CONFIG_DEFS_ONLY}\" != \"yes\" &amp;&amp; \"${PRE_PREPARED_HOST}\" != \"yes\" ]] &amp;&amp; git_ensure_safe_directory \"${SRC}\"<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">6. cli_entrypoint &#8220;$@&#8221;\u51fd\u6570\uff08\u4f4d\u4e8e.\/lib\/functions\/cli\/entrypoint.sh\uff09<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">6.1 \u8c03\u7528\u8ddf\u8e2a\u529f\u80fd<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\tif &#91;&#91; \"${ARMBIAN_ENABLE_CALL_TRACING}\" == \"yes\" ]]; then\n\t\tset -T # inherit return\/debug traps\n\t\tmkdir -p \"${SRC}\"\/output\/call-traces\n\t\techo -n \"\" > \"${SRC}\"\/output\/call-traces\/calls.txt\n\t\t# See https:\/\/www.gnu.org\/software\/bash\/manual\/html_node\/Bash-Variables.html\n\t\ttrap 'echo \"${FUNCNAME&#91;*]}|${BASH_LINENO&#91;*]}|${BASH_SOURCE&#91;*]}|${LINENO}\" >> ${SRC}\/output\/call-traces\/calls.txt ;' RETURN\n\tfi<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">6.2 \u6620\u5c04\u547d\u4ee4\u5230\u5b83\u4eec\u7684\u5904\u7406\u51fd\u6570\u4ee5\u53ca\u76f8\u5173\u7684\u53d8\u91cf\u8bbe\u7f6e<\/h3>\n\n\n\n<p><code>armbian_register_commands<\/code>\u4f4d\u4e8e<code>lib\/functions\/cli\/commands.sh<\/code>\uff0c\u901a\u8fc7\u5173\u8054\u6570\u7ec4\u5b9e\u73b0\u5b57\u5178\u7684\u529f\u80fd <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t# Decide what we're gonna do. We've a few hardcoded, 1st-argument \"commands\".\n\tdeclare -g -A ARMBIAN_COMMANDS_TO_HANDLERS_DICT ARMBIAN_COMMANDS_TO_VARS_DICT\n\tarmbian_register_commands # this defines the above two dictionaries<\/code><\/pre>\n\n\n\n<p><strong>ARMBIAN_COMMANDS_TO_HANDLERS_DICT<\/strong>: \u8fd9\u4e2a\u5173\u8054\u6570\u7ec4\u6620\u5c04\u4e86\u4e00\u7cfb\u5217\u547d\u4ee4\u5b57\u7b26\u4e32\u5230\u5b83\u4eec\u5bf9\u5e94\u7684\u5904\u7406\u51fd\u6570\u540d\u79f0\u3002\u4f8b\u5982\uff0c\u591a\u4e2a\u4e0e <code>docker<\/code> \u76f8\u5173\u7684\u547d\u4ee4\u90fd\u6620\u5c04\u5230\u4e86\u540c\u4e00\u4e2a\u5904\u7406\u51fd\u6570 <code>docker<\/code><\/p>\n\n\n\n<p><strong>ARMBIAN_COMMANDS_TO_VARS_DICT<\/strong>: \u8fd9\u4e2a\u5173\u8054\u6570\u7ec4\u4e3a\u7279\u5b9a\u7684\u547d\u4ee4\u63d0\u4f9b\u4e86\u9700\u8981\u8bbe\u7f6e\u7684\u53d8\u91cf\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.3 \u5904\u7406\u547d\u4ee4\u884c\u53c2\u6570<\/h3>\n\n\n\n<p><code>parse_cmdline_params<\/code>\u4f4d\u4e8e<code>lib\/functions\/cli\/utils-cli.sh<\/code>\uff0c\u7528\u4e8e\u5c06\u53c2\u6570\u5206\u4e3a\u4e24\u7c7b\u3002 <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t# Process the command line, separating params (XX=YY) from non-params arguments.\n\t# That way they can be set in any order.\n\tdeclare -A -g ARMBIAN_PARSED_CMDLINE_PARAMS=() # A dict of PARAM=VALUE\n\tdeclare -a -g ARMBIAN_NON_PARAM_ARGS=()        # An array of all non-param arguments\n\tparse_cmdline_params \"${@}\"                    # which fills the above vars.<\/code><\/pre>\n\n\n\n<p><strong>ARMBIAN_PARSED_CMDLINE_PARAMS<\/strong>\uff0c\u7528\u4e8e\u5b58\u50a8\u5f62\u5f0f\u4e3a <code>PARAM=VALUE<\/code> \u7684\u547d\u4ee4\u884c\u53c2\u6570\uff1b<\/p>\n\n\n\n<p><strong>ARMBIAN_NON_PARAM_ARGS<\/strong>\uff0c\u7528\u4e8e\u5b58\u50a8\u975e\u53c2\u6570\u7c7b\u7684\u547d\u4ee4\u884c\u53c2\u6570\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.4 \u73af\u5883\u53d8\u91cf\u5e94\u7528\u4e0e\u65e5\u5fd7\u521d\u59cb\u5316<\/h3>\n\n\n\n<p><code>apply_cmdline_params_to_env<\/code>\u4f4d\u4e8e<code>lib\/functions\/cli\/utils-cli.sh<\/code>\uff0c\u7528\u4e8e\u5c06\u952e\u503c\u7c7b\u578b\u7684\u53c2\u6570\u5e94\u7528\u5230\u811a\u672c\u73af\u5883\u3002 <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t# Now load the key=value pairs from cmdline into environment, before loading config or executing commands.\n\t# This will be done _again_ later, to make sure cmdline params override config et al.\n\tapply_cmdline_params_to_env \"early\" # which uses ARMBIAN_PARSED_CMDLINE_PARAMS\n\t# From here on, no more ${1} or stuff. We've parsed it all into ARMBIAN_PARSED_CMDLINE_PARAMS or ARMBIAN_NON_PARAM_ARGS and ARMBIAN_COMMAND.\n\n\t# Re-initialize logging, to take into account the new environment after parsing cmdline params.\n\tlogging_init<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">6.5 \u5904\u7406\u914d\u7f6e\u6216\u914d\u7f6e\u6587\u4ef6<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\tdeclare -a -g ARMBIAN_CONFIG_FILES=()                                            # fully validated, complete paths to config files.\n\tdeclare -g ARMBIAN_COMMAND_HANDLER=\"\" ARMBIAN_COMMAND=\"\" ARMBIAN_COMMAND_VARS=\"\" # only valid command and handler will ever be set here.\n\tdeclare -g ARMBIAN_HAS_UNKNOWN_ARG=\"no\"                                          # if any unknown params, bomb.\n\tfor argument in \"${ARMBIAN_NON_PARAM_ARGS&#91;@]}\"; do                               # loop over all non-param arguments, find commands and configs.\n\t\tparse_each_cmdline_arg_as_command_param_or_config \"${argument}\"                 # sets all the vars above\n\tdone<\/code><\/pre>\n\n\n\n<p><strong>ARMBIAN_CONFIG_FILES<\/strong>\uff0c\u5168\u5c40\u7684\u7d22\u5f15\u6570\u7ec4\uff0c\u7528\u4e8e\u5b58\u50a8\u5b8c\u5168\u9a8c\u8bc1\u540e\u7684\u914d\u7f6e\u6587\u4ef6\u8def\u5f84\uff1b<\/p>\n\n\n\n<p><code>parse_each_cmdline_arg_as_command_param_or_config<\/code>\u4f4d\u4e8e<code>lib\/functions\/cli\/utils-cli.sh<\/code>\uff0c\u68c0\u6d4b\u8f93\u5165\u662f\u547d\u4ee4\u8fd8\u662f\u914d\u7f6e\u6587\u4ef6\uff0c\u5982\u679c\u53c2\u6570\u88ab\u8bc6\u522b\u4e3a\u914d\u7f6e\u6587\u4ef6\uff0c\u5c06\u5176\u8def\u5f84\u6dfb\u52a0\u5230 <strong>ARMBIAN_CONFIG_FILES<\/strong>\u6570\u7ec4\u4e2d\uff0c\u5e76\u5c06\u6587\u4ef6\u540d\u6dfb\u52a0\u5230 <strong>ARMBIAN_CLI_RELAUNCH_CONFIGS <\/strong>\u6570\u7ec4\u4e2d\uff0c\u5c06\u53c2\u6570\u8bbe\u7f6e\u4e3a<strong>ARMBIAN_COMMAND<\/strong><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.6 \u547d\u4ee4\u9884\u5904\u7406<\/h3>\n\n\n\n<p>\u5728\u6267\u884c\u6700\u7ec8\u547d\u4ee4\u4e4b\u524d\uff0c\u68c0\u67e5\u662f\u5426\u6709\u9700\u8981\u9884\u5148\u6267\u884c\u7684\u547d\u4ee4\uff0c\u5e76\u8fdb\u884c\u76f8\u5e94\u7684\u5904\u7406\u3002<code>armbian_prepare_cli_command_to_run<\/code>\u4f4d\u4e8e.\/build\/lib\/cli\/utils-cli.sh<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t# If we don't have a command at this stage, we should default either to 'build' or 'docker', depending on OS.\n\t# Give the chosen command a chance to refuse running, or, even, change the final command to run.\n\t# This allows for example the 'build' command to auto-launch under docker, even without specifying it.\n\t# Also allows for launchers to keep themselves when re-launched, yet do something diferent. (eg: docker under docker does build).\n\t# Or: build under Darwin does docker...\n\t# each _pre_run can change the command and vars to run too, so do it in a loop until it stops changing.\n\tdeclare -g ARMBIAN_CHANGE_COMMAND_TO=\"${ARMBIAN_COMMAND}\"\n\twhile &#91;&#91; \"${ARMBIAN_CHANGE_COMMAND_TO}\" != \"\" ]]; do\n\t\tdisplay_alert \"Still a command to pre-run, this time:\" \"${ARMBIAN_CHANGE_COMMAND_TO}\" \"debug\"\n\n\t\tdeclare -g ARMBIAN_COMMAND_REQUIRE_BASIC_DEPS=\"no\" # reset this before every pre_run, so only the last one wins.\n\t\tARMBIAN_COMMAND=\"${ARMBIAN_CHANGE_COMMAND_TO}\"\n\t\tarmbian_prepare_cli_command_to_run \"${ARMBIAN_COMMAND}\"\n\n\t\tARMBIAN_CHANGE_COMMAND_TO=\"\"\n\t\tarmbian_cli_pre_run_command\n\tdone<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">6.7 \u76ee\u5f55\u521d\u59cb\u5316<\/h3>\n\n\n\n<p>.\/output\u76ee\u5f55\u548c.\/userpatches <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\t# Init basic dirs.\n\tdeclare -g -r DEST=\"${SRC}\/output\" USERPATCHES_PATH=\"${SRC}\"\/userpatches # DEST is the main output dir, and USERPATCHES_PATH is the userpatches dir. read-only.\n\tmkdir -p \"${DEST}\" \"${USERPATCHES_PATH}\"                                 # Create output and userpatches directory if not already there\n\tdisplay_alert \"Output directory created! DEST:\" \"${DEST}\" \"debug\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">6.8 \u751f\u6210UUID<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\t# set unique mounting directory for this execution.\n\t# basic deps, which include \"uuidgen\", will be installed _after_ this, so we gotta tolerate it not being there yet.\n\tdeclare -g ARMBIAN_BUILD_UUID\n\tif &#91;&#91; \"${ARMBIAN_BUILD_UUID}\" != \"\" ]]; then\n\t\tdisplay_alert \"Using passed-in ARMBIAN_BUILD_UUID\" \"${ARMBIAN_BUILD_UUID}\" \"debug\"\n\telse\n\t\tif command -v uuidgen 1> \/dev\/null; then\n\t\t\tARMBIAN_BUILD_UUID=\"$(uuidgen)\"\n\t\telse\n\t\t\tdisplay_alert \"uuidgen not found\" \"uuidgen not installed yet\" \"info\"\n\t\t\tARMBIAN_BUILD_UUID=\"no-uuidgen-yet-${RANDOM}-$((1 + $RANDOM % 10))$((1 + $RANDOM % 10))$((1 + $RANDOM % 10))$((1 + $RANDOM % 10))\"\n\t\tfi\n\t\tdisplay_alert \"Generated ARMBIAN_BUILD_UUID\" \"${ARMBIAN_BUILD_UUID}\" \"debug\"\n\tfi\n\tdeclare -g -r ARMBIAN_BUILD_UUID=\"${ARMBIAN_BUILD_UUID}\" # Make read-only\n\tdisplay_alert \"Build UUID:\" \"${ARMBIAN_BUILD_UUID}\" \"debug\"<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">6.9 \u65e5\u5fd7\u548c\u6e05\u7406\u5904\u7406<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code># Super-global variables, used everywhere. The directories are NOT _created_ here, since this very early stage. They are all readonly, for sanity.\n\tdeclare -g -r WORKDIR_BASE_TMP=\"${SRC}\/.tmp\" # a.k.a. \".tmp\" dir. it is a shared base dir for all builds, but each build gets its own WORKDIR\/TMPDIR.\n\n\tdeclare -g -r WORKDIR=\"${WORKDIR_BASE_TMP}\/work-${ARMBIAN_BUILD_UUID}\"                         # WORKDIR at this stage. It will become TMPDIR later. It has special significance to `mktemp` and others!\n\tdeclare -g -r LOGDIR=\"${WORKDIR_BASE_TMP}\/logs-${ARMBIAN_BUILD_UUID}\"                          # Will be initialized very soon, literally, below.\n\tdeclare -g -r EXTENSION_MANAGER_TMP_DIR=\"${WORKDIR_BASE_TMP}\/extensions-${ARMBIAN_BUILD_UUID}\" # EXTENSION_MANAGER_TMP_DIR used to store extension-composed functions\n\n\t# @TODO: These are used only by rootfs\/image actual build, move there...\n\tdeclare -g -r SDCARD=\"${WORKDIR_BASE_TMP}\/rootfs-${ARMBIAN_BUILD_UUID}\" # SDCARD (which is NOT an sdcard, but will be, maybe, one day) is where we work the rootfs before final imaging. \"rootfs\" stage.\n\tdeclare -g -r MOUNT=\"${WORKDIR_BASE_TMP}\/mount-${ARMBIAN_BUILD_UUID}\"   # MOUNT (\"mounted on the loop\") is the mounted root on final image (via loop). \"image\" stage\n\tdeclare -g -r DESTIMG=\"${WORKDIR_BASE_TMP}\/image-${ARMBIAN_BUILD_UUID}\" # DESTIMG is where the backing image (raw, huge, sparse file) is kept (not the final destination)\n\n\t# Make sure ARMBIAN_LOG_CLI_ID is set, and unique, and readonly.\n\t# Pre-runs might change it before this, but if not set, default to ARMBIAN_COMMAND.\n\tdeclare -r -g ARMBIAN_LOG_CLI_ID=\"${ARMBIAN_LOG_CLI_ID:-${ARMBIAN_COMMAND}}\"\n\n\t# If we're on Linux &amp; root, mount tmpfs on LOGDIR. This has it's own cleanup handler.\n\t# It also _creates_ the LOGDIR, and the cleanup handler will delete.\n\tprepare_tmpfs_for \"LOGDIR\" \"${LOGDIR}\"\n\n\tLOG_SECTION=\"entrypoint\" start_logging_section      # This will create LOGDIR if it does not exist. @TODO: also maybe causes a spurious group to be created in the log file\n\tadd_cleanup_handler trap_handler_cleanup_logging    # cleanup handler for logs; it rolls it up from LOGDIR into DEST\/logs\n\tadd_cleanup_handler trap_handler_reset_output_owner # make sure output folder is owned by pre-sudo\/pre-Docker user if that's the case<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">6.10 \u57fa\u7840\u4f9d\u8d56\u68c0\u67e5<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\t# @TODO: So gigantic contention point here about logging the basic deps installation.\n\tif &#91;&#91; \"${ARMBIAN_COMMAND_REQUIRE_BASIC_DEPS}\" == \"yes\" ]]; then\n\t\tif &#91;&#91; \"${OFFLINE_WORK}\" == \"yes\" ]]; then\n\t\t\tdisplay_alert \"* \" \"You are working offline!\"\n\t\t\tdisplay_alert \"* \" \"Sources, time and host will not be checked\"\n\t\telse\n\t\t\t# check and install the basic utilities;\n\t\t\tLOG_SECTION=\"prepare_host_basic\" do_with_logging prepare_host_basic # This includes the 'docker' case.\n\t\tfi\n\tfi<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">6.11 \u914d\u7f6e\u6587\u4ef6\u52a0\u8f7d<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\t# Loop over the ARMBIAN_CONFIG_FILES array and source each. The order is important.\n\tfor config_file in \"${ARMBIAN_CONFIG_FILES&#91;@]}\"; do\n\t\tlocal config_filename=\"${config_file##*\/}\" config_dir=\"${config_file%\/*}\"\n\t\tdisplay_alert \"Sourcing config file\" \"${config_filename}\" \"debug\"\n\n\t\t# use pushd\/popd to change directory to the config file's directory, so that relative paths in the config file work.\n\t\tpushd \"${config_dir}\" > \/dev\/null || exit_with_error \"Failed to pushd to ${config_dir}\"\n\n\t\t# shellcheck source=\/dev\/null\n\t\tLOG_SECTION=\"userpatches_config:${config_filename}\" do_with_logging source \"${config_file}\"\n\n\t\t# reset completely after sourcing config file\n\t\tset -e\n\t\t#set -o pipefail  # trace ERR through pipes - will be enabled \"soon\"\n\t\t#set -o nounset   ## set -u : exit the script if you try to use an uninitialised variable - one day will be enabled\n\t\tset -o errtrace # trace ERR through - enabled\n\t\tset -o errexit  ## set -e : exit the script if any statement returns a non-true return value - enabled\n\n\t\tpopd > \/dev\/null || exit_with_error \"Failed to popd from ${config_dir}\"\n\n\t\t# Apply the params received from the command line _again_ after running the config.\n\t\t# This ensures that params take precedence over stuff possibly defined in the config.\n\t\tapply_cmdline_params_to_env \"after config '${config_filename}'\" # which uses ARMBIAN_PARSED_CMDLINE_PARAMS\n\tdone<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">6.12 \u6267\u884c\u6700\u7ec8\u547d\u4ee4<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>\t# Early check for deprecations\n\terror_if_lib_tag_set # make sure users are not thrown off by using old parameter which does nothing anymore; explain\n\n\tdisplay_alert \"Executing final CLI command\" \"${ARMBIAN_COMMAND}\" \"debug\"\n\tarmbian_cli_run_command\n\tdisplay_alert \"Done Executing final CLI command\" \"${ARMBIAN_COMMAND}\" \"debug\"\n\n\t# Build done, run the cleanup handlers explicitly.\n\t# This zeroes out the list of cleanups, so it\"s not done again when the main script exits normally and trap = 0 runs.\n\trun_cleanup_handlers<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>1. \u811a\u672c\u76ee\u5f55\u68c0\u6d4b\u548c\u4ee3\u7801\u5065\u58ee\u6027\u4fdd\u8bc1 1.1 \u7a0b\u5e8f\u62a5\u9519\u9000\u51fa\u811a\u672c 1.2. .\/compile.sh\u811a\u672c\u76ee\u5f55\u68c0\u6d4b  [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v17.6 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Armbian\/build\u811a\u672c\u5206\u6790 &ndash; Laning &#039;s Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Armbian\/build\u811a\u672c\u5206\u6790 &ndash; Laning &#039;s Blog\" \/>\n<meta property=\"og:description\" content=\"1. \u811a\u672c\u76ee\u5f55\u68c0\u6d4b\u548c\u4ee3\u7801\u5065\u58ee\u6027\u4fdd\u8bc1 1.1 \u7a0b\u5e8f\u62a5\u9519\u9000\u51fa\u811a\u672c 1.2. .\/compile.sh\u811a\u672c\u76ee\u5f55\u68c0\u6d4b [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/\" \/>\n<meta property=\"og:site_name\" content=\"Laning &#039;s Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-06-06T05:44:10+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-06-06T05:45:50+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u4f5c\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"laning\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data2\" content=\"11\u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/blog.laning.org\/#website\",\"url\":\"https:\/\/blog.laning.org\/\",\"name\":\"\\u8fa3\\u5b81\\u7684\\u535a\\u5ba2\",\"description\":\"Learning on the go\",\"publisher\":{\"@id\":\"https:\/\/blog.laning.org\/#\/schema\/person\/040331b403ed00370f2fc1e8eb6e6b93\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/blog.laning.org\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"zh-CN\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#webpage\",\"url\":\"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/\",\"name\":\"Armbian\/build\\u811a\\u672c\\u5206\\u6790 &ndash; Laning &#039;s Blog\",\"isPartOf\":{\"@id\":\"https:\/\/blog.laning.org\/#website\"},\"datePublished\":\"2024-06-06T05:44:10+00:00\",\"dateModified\":\"2024-06-06T05:45:50+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#breadcrumb\"},\"inLanguage\":\"zh-CN\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\\u9996\\u9875\",\"item\":\"https:\/\/blog.laning.org\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Armbian\/build\\u811a\\u672c\\u5206\\u6790\"}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#webpage\"},\"author\":{\"@id\":\"https:\/\/blog.laning.org\/#\/schema\/person\/040331b403ed00370f2fc1e8eb6e6b93\"},\"headline\":\"Armbian\/build\\u811a\\u672c\\u5206\\u6790\",\"datePublished\":\"2024-06-06T05:44:10+00:00\",\"dateModified\":\"2024-06-06T05:45:50+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#webpage\"},\"wordCount\":93,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/blog.laning.org\/#\/schema\/person\/040331b403ed00370f2fc1e8eb6e6b93\"},\"articleSection\":[\"Github\"],\"inLanguage\":\"zh-CN\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#respond\"]}]},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/blog.laning.org\/#\/schema\/person\/040331b403ed00370f2fc1e8eb6e6b93\",\"name\":\"laning\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/blog.laning.org\/#personlogo\",\"inLanguage\":\"zh-CN\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/17215f328425d53537532588320693a1?s=96&d=retro&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/17215f328425d53537532588320693a1?s=96&d=retro&r=g\",\"caption\":\"laning\"},\"logo\":{\"@id\":\"https:\/\/blog.laning.org\/#personlogo\"},\"sameAs\":[\"https:\/\/blog.laning.org\"],\"url\":\"https:\/\/blog.laning.org\/index.php\/author\/laning\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Armbian\/build\u811a\u672c\u5206\u6790 &ndash; Laning &#039;s Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/","og_locale":"zh_CN","og_type":"article","og_title":"Armbian\/build\u811a\u672c\u5206\u6790 &ndash; Laning &#039;s Blog","og_description":"1. \u811a\u672c\u76ee\u5f55\u68c0\u6d4b\u548c\u4ee3\u7801\u5065\u58ee\u6027\u4fdd\u8bc1 1.1 \u7a0b\u5e8f\u62a5\u9519\u9000\u51fa\u811a\u672c 1.2. .\/compile.sh\u811a\u672c\u76ee\u5f55\u68c0\u6d4b [&hellip;]","og_url":"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/","og_site_name":"Laning &#039;s Blog","article_published_time":"2024-06-06T05:44:10+00:00","article_modified_time":"2024-06-06T05:45:50+00:00","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"laning","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"11\u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebSite","@id":"https:\/\/blog.laning.org\/#website","url":"https:\/\/blog.laning.org\/","name":"\u8fa3\u5b81\u7684\u535a\u5ba2","description":"Learning on the go","publisher":{"@id":"https:\/\/blog.laning.org\/#\/schema\/person\/040331b403ed00370f2fc1e8eb6e6b93"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blog.laning.org\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"zh-CN"},{"@type":"WebPage","@id":"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#webpage","url":"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/","name":"Armbian\/build\u811a\u672c\u5206\u6790 &ndash; Laning &#039;s Blog","isPartOf":{"@id":"https:\/\/blog.laning.org\/#website"},"datePublished":"2024-06-06T05:44:10+00:00","dateModified":"2024-06-06T05:45:50+00:00","breadcrumb":{"@id":"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#breadcrumb"},"inLanguage":"zh-CN","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/blog.laning.org\/"},{"@type":"ListItem","position":2,"name":"Armbian\/build\u811a\u672c\u5206\u6790"}]},{"@type":"Article","@id":"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#article","isPartOf":{"@id":"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#webpage"},"author":{"@id":"https:\/\/blog.laning.org\/#\/schema\/person\/040331b403ed00370f2fc1e8eb6e6b93"},"headline":"Armbian\/build\u811a\u672c\u5206\u6790","datePublished":"2024-06-06T05:44:10+00:00","dateModified":"2024-06-06T05:45:50+00:00","mainEntityOfPage":{"@id":"https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#webpage"},"wordCount":93,"commentCount":0,"publisher":{"@id":"https:\/\/blog.laning.org\/#\/schema\/person\/040331b403ed00370f2fc1e8eb6e6b93"},"articleSection":["Github"],"inLanguage":"zh-CN","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/blog.laning.org\/index.php\/2024\/06\/06\/380\/#respond"]}]},{"@type":["Person","Organization"],"@id":"https:\/\/blog.laning.org\/#\/schema\/person\/040331b403ed00370f2fc1e8eb6e6b93","name":"laning","image":{"@type":"ImageObject","@id":"https:\/\/blog.laning.org\/#personlogo","inLanguage":"zh-CN","url":"https:\/\/secure.gravatar.com\/avatar\/17215f328425d53537532588320693a1?s=96&d=retro&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/17215f328425d53537532588320693a1?s=96&d=retro&r=g","caption":"laning"},"logo":{"@id":"https:\/\/blog.laning.org\/#personlogo"},"sameAs":["https:\/\/blog.laning.org"],"url":"https:\/\/blog.laning.org\/index.php\/author\/laning\/"}]}},"_links":{"self":[{"href":"https:\/\/blog.laning.org\/index.php\/wp-json\/wp\/v2\/posts\/380"}],"collection":[{"href":"https:\/\/blog.laning.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.laning.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.laning.org\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.laning.org\/index.php\/wp-json\/wp\/v2\/comments?post=380"}],"version-history":[{"count":13,"href":"https:\/\/blog.laning.org\/index.php\/wp-json\/wp\/v2\/posts\/380\/revisions"}],"predecessor-version":[{"id":393,"href":"https:\/\/blog.laning.org\/index.php\/wp-json\/wp\/v2\/posts\/380\/revisions\/393"}],"wp:attachment":[{"href":"https:\/\/blog.laning.org\/index.php\/wp-json\/wp\/v2\/media?parent=380"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.laning.org\/index.php\/wp-json\/wp\/v2\/categories?post=380"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.laning.org\/index.php\/wp-json\/wp\/v2\/tags?post=380"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}