当前位置: 首页 > news >正文

debug - MDK - arm-none-eabi - 从MDK工程做一个makefile工程出来

文章目录

    • debug - MDK - arm-none-eabi - 从MDK工程做一个makefile工程出来
    • 概述
    • 笔记
      • my_arm_gnu_env_only.bat
    • 先将编译结果整理成一个bat
      • build.bat
      • 运行效果
    • makefile v0.1
    • makefile v0.2
    • makefile v0.4
    • makefile v0.5
    • makefile v0.6
    • makefile v0.7
    • makefile v0.8
    • makefile v0.9
    • 最终编译效果
    • 备注
    • 备注
    • 备注
    • END

debug - MDK - arm-none-eabi - 从MDK工程做一个makefile工程出来

概述

想从一个基于arm-gcc工具链编译的MDK工程,做一个makefile工程出来。
达到和MDK工程编译一摸一样的效果。

前面做了实验(debug - MDK - arm-none-eabi - 将MDK工程编译过程的所有命令行参数找出来), 已经将MDK工程编译时的全部命令行编译参数找出来了。

现在整理一个makefile出来。

笔记

my_arm_gnu_env_only.bat

先写一个带有arm-gcc环境和gnu-make环境的脚本.

@echo off
rem @file my_arm_gnu_env_only.bat
rem @breif 通用的arm-gcc工具链,编译哪个工程都可以
set path=%~dp0arm-gnu-toolchain\bin;%~dp0gnuwin32\bin;%~dp0curl;%path%
rem set path=C:\nxp\MCUXpressoIDE_25.6.136\ide\;%path%
cmd /k "echo my arm gnu env"

先将编译结果整理成一个bat

为了清晰,先将前面实验找出来的全部命令行参数先要用.bat表达出来,先能干活, 然后再整理成makefile, 这样清晰简单。

build.bat

@echo off
rem @file build.batclsrem 打印bat文件的全路径名称
echo %~f0echo.
echo ------------------------------------------------------------echo BEGINecho.
echo ------------------------------------------------------------
echo cleanrem 路径符号必须是用'\'rem 建立必须存在的文件夹
if not exist .\out mkdir .\outrem 删除中间文件
if exist ".\*.o" (echo del .\*.odel .\*.o
)if exist ".\out\*.o" (echo del .\out\*.odel .\out\*.o
)if exist ".\out\*.map" (echo del .\out\*.mapdel .\out\*.map
)if exist ".\out\*.elf" (echo del .\out\*.elfdel .\out\*.elf
)if exist ".\out\*.d" (echo del .\out\*.ddel .\out\*.d
)if exist ".\out\*.hex" (echo del .\out\*.hexdel .\out\*.hex
)if exist ".\out\*.lst" (echo del .\out\*.lstdel .\out\*.lst
)echo.
dir /s /b /onegecho.
echo ------------------------------------------------------------
echo compilerem 如果不指定输出名称, 就是同名的.o
rem arm-none-eabi-gcc -c main.crem compile .s
arm-none-eabi-as ^-mcpu=cortex-m3 -mthumb --gdwarf-2 -mthumb-interwork ^-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" ^-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" ^-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" ^-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" ^--defsym __UVISION_VERSION=543 ^--defsym __GCC=1 ^--defsym __GCC_VERSION=1431 ^--defsym LPC175x_6x=1 ^-alhms=./out/startup_lpc17xx.lst ^--MD ./out/startup_lpc17xx.d ^-o ./out/startup_lpc17xx.o "src/startup_LPC17xx.s"arm-none-eabi-gcc ^-c ^-mcpu=cortex-m3 -mthumb -gdwarf-2 -MMD -pedantic -O0 -mapcs-frame -mthumb-interwork ^-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" ^-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" ^-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" ^-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" ^-D__UVISION_VERSION="543" ^-D__GCC -D__GCC_VERSION="1431" ^-DLPC175x_6x ^-Wa,-alhms=./out/main.lst ^-o ./out/main.o "src/main.cpp"echo.
echo ------------------------------------------------------------
echo Linkarm-none-eabi-gcc ^-T ./src/LPC1768.ld ^-mcpu=cortex-m3 -mthumb -mthumb-interwork -Wl,-Map="./out/arm-gcc.map" -nostartfiles ^-o "./out/arm-gcc.elf" "./out/startup_lpc17xx.o" "./out/main.o"echo.
echo ------------------------------------------------------------
echo convertrem exe 可以用双引号包裹起来
"arm-none-eabi-objcopy.exe" -O ihex ./out/arm-gcc.elf ./out/arm-gcc.hexecho.
dir /s /b /onegecho.
echo ------------------------------------------------------------
echo END

运行效果

在cmd中先运行包含arm-gcc环境的脚本my_arm_gnu_env_only.bat,然后再运行build.bat

D:\my_dev\my_test\arm-gcc-makefile\v0.1\build.bat------------------------------------------------------------
BEGIN------------------------------------------------------------
clean
del .\out\*.o
del .\out\*.map
del .\out\*.elf
del .\out\*.d
del .\out\*.hex
del .\out\*.lstD:\my_dev\my_test\arm-gcc-makefile\v0.1\build.bat
D:\my_dev\my_test\arm-gcc-makefile\v0.1\out
D:\my_dev\my_test\arm-gcc-makefile\v0.1\src
D:\my_dev\my_test\arm-gcc-makefile\v0.1\src\LPC1768.ld
D:\my_dev\my_test\arm-gcc-makefile\v0.1\src\main.cpp
D:\my_dev\my_test\arm-gcc-makefile\v0.1\src\startup_LPC17xx.s------------------------------------------------------------
compile------------------------------------------------------------
Link------------------------------------------------------------
convertD:\my_dev\my_test\arm-gcc-makefile\v0.1\build.bat
D:\my_dev\my_test\arm-gcc-makefile\v0.1\out
D:\my_dev\my_test\arm-gcc-makefile\v0.1\src
D:\my_dev\my_test\arm-gcc-makefile\v0.1\out\arm-gcc.elf
D:\my_dev\my_test\arm-gcc-makefile\v0.1\out\arm-gcc.hex
D:\my_dev\my_test\arm-gcc-makefile\v0.1\out\arm-gcc.map
D:\my_dev\my_test\arm-gcc-makefile\v0.1\out\main.d
D:\my_dev\my_test\arm-gcc-makefile\v0.1\out\main.lst
D:\my_dev\my_test\arm-gcc-makefile\v0.1\out\main.o
D:\my_dev\my_test\arm-gcc-makefile\v0.1\out\startup_lpc17xx.d
D:\my_dev\my_test\arm-gcc-makefile\v0.1\out\startup_lpc17xx.lst
D:\my_dev\my_test\arm-gcc-makefile\v0.1\out\startup_lpc17xx.o
D:\my_dev\my_test\arm-gcc-makefile\v0.1\src\LPC1768.ld
D:\my_dev\my_test\arm-gcc-makefile\v0.1\src\main.cpp
D:\my_dev\my_test\arm-gcc-makefile\v0.1\src\startup_LPC17xx.s------------------------------------------------------------
ENDD:\my_dev\my_test\arm-gcc-makefile\v0.1>

makefile v0.1

从bat直接翻译一个最简单的makefile

# @file makefile
# @brief 从build.bat进化出来的makefile
#	v0.1 最简单的makefile, 从.bat直接改过来# makefile_obj : depend(可选)
#	action
# makefile_obj从行首开始
# action必须从TAB键开始
# 命令之前加@, 就关掉了echo回显all:@cls@if not exist ".\out" mkdir ".\out"@if exist ".\out\*" del /q ".\out\*"@echo ----------------------------------------@echo before build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------arm-none-eabi-as \-mcpu=cortex-m3 -mthumb --gdwarf-2 -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \--defsym __UVISION_VERSION=543 \--defsym __GCC=1 \--defsym __GCC_VERSION=1431 \--defsym LPC175x_6x=1 \-alhms=./out/startup_lpc17xx.lst \--MD ./out/startup_lpc17xx.d \-o ./out/startup_lpc17xx.o "src/startup_LPC17xx.s"arm-none-eabi-gcc \-c \-mcpu=cortex-m3 -mthumb -gdwarf-2 -MMD -pedantic -O0 -mapcs-frame -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \-D__UVISION_VERSION="543" \-D__GCC -D__GCC_VERSION="1431" \-DLPC175x_6x \-Wa,-alhms=./out/main.lst \-o ./out/main.o "src/main.cpp"arm-none-eabi-gcc \-T ./src/LPC1768.ld \-mcpu=cortex-m3 -mthumb -mthumb-interwork -Wl,-Map="./out/arm-gcc.map" -nostartfiles \-o "./out/arm-gcc.elf" "./out/startup_lpc17xx.o" "./out/main.o"arm-none-eabi-objcopy -O ihex ./out/arm-gcc.elf ./out/arm-gcc.hex@echo ----------------------------------------@echo after build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------

makefile v0.2

加入编译目标的依赖,依赖的实现变了,就编译。如果实现没变,就不编译

# @file makefile
# @brief 从build.bat进化出来的makefile
#	v0.2 加入编译目标的依赖,提高编译效率
#	v0.1 最简单的makefile, 从.bat直接改过来# makefile_obj : depend(可选)
#	action
# makefile_obj从行首开始
# action必须从TAB键开始
# 命令之前加@, 就关掉了echo回显all: ./out/startup_lpc17xx.o ./out/main.o ./out/arm-gcc.elfclean:@cls@if not exist ".\out" mkdir ".\out"@if exist ".\out\*" del /q ".\out\*"@echo ----------------------------------------@echo before build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------./out/startup_lpc17xx.o: src/startup_LPC17xx.sarm-none-eabi-as \-mcpu=cortex-m3 -mthumb --gdwarf-2 -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \--defsym __UVISION_VERSION=543 \--defsym __GCC=1 \--defsym __GCC_VERSION=1431 \--defsym LPC175x_6x=1 \-alhms=./out/startup_lpc17xx.lst \--MD ./out/startup_lpc17xx.d \-o ./out/startup_lpc17xx.o "src/startup_LPC17xx.s"./out/main.o: src/main.cpparm-none-eabi-gcc \-c \-mcpu=cortex-m3 -mthumb -gdwarf-2 -MMD -pedantic -O0 -mapcs-frame -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \-D__UVISION_VERSION="543" \-D__GCC -D__GCC_VERSION="1431" \-DLPC175x_6x \-Wa,-alhms=./out/main.lst \-o ./out/main.o "src/main.cpp"./out/arm-gcc.elf: ./out/startup_lpc17xx.o ./src/LPC1768.ld ./out/main.oarm-none-eabi-gcc \-T ./src/LPC1768.ld \-mcpu=cortex-m3 -mthumb -mthumb-interwork -Wl,-Map="./out/arm-gcc.map" -nostartfiles \-o "./out/arm-gcc.elf" "./out/startup_lpc17xx.o" "./out/main.o"arm-none-eabi-objcopy -O ihex ./out/arm-gcc.elf ./out/arm-gcc.hex@echo ----------------------------------------@echo after build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------

makefile v0.4

# @file makefile
# @brief 从build.bat进化出来的makefile
#	v0.4 确认和验证是否实际目标可以写成伪目标, 答案是不能(会失去文件自动检测编译的功能,导致全部编译)
#	v0.3 声明伪目标, 加入编译目标 rebuild
#	v0.2 加入编译目标的依赖,提高编译效率
#	v0.1 最简单的makefile, 从.bat直接改过来# makefile_obj : depend(可选)
#	action
# makefile_obj从行首开始
# action必须从TAB键开始
# 命令之前加@, 就关掉了echo回显# 如果多个编译目标的规则都相同,可以将多个目标放在一起,用空格分开
# e.g. 
# obj1 obj2: main.cpp
# gcc -xx ...# 在编译目标的gcc命令中使用的自动变量
# @$ 当前目标
# @< 依赖的第一个文件
# -o @$ @< # 要编译的文件比较多时, 可以代替硬编码# c_file: src/*.c
# 如果编译目标指定的依赖不存在,makefile会报错
# 如果没有的实际目标,就不要留在makefile中# 编译具体目标时, 不能写成伪目标,而是要直接写成真正要编译的.o目标,否则就不能检测依赖的文件变化了,而是每次都全部编译.PHONY: all clean rebuildall: \./out/arm-gcc.elf@echo build allrebuild:make cleanmakeclean:@cls@if not exist ".\out" mkdir ".\out"@if exist ".\out\*" del /q ".\out\*"@echo ----------------------------------------@echo before build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------./out/startup_lpc17xx.o: src/startup_lpc17xx.sarm-none-eabi-as \-mcpu=cortex-m3 -mthumb --gdwarf-2 -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \--defsym __UVISION_VERSION=543 \--defsym __GCC=1 \--defsym __GCC_VERSION=1431 \--defsym LPC175x_6x=1 \-alhms=./out/startup_lpc17xx.lst \--MD ./out/startup_lpc17xx.d \-o ./out/startup_lpc17xx.o "src/startup_LPC17xx.s"./out/main.o: src/main.cpparm-none-eabi-gcc \-c \-mcpu=cortex-m3 -mthumb -gdwarf-2 -MMD -pedantic -O0 -mapcs-frame -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \-D__UVISION_VERSION="543" \-D__GCC -D__GCC_VERSION="1431" \-DLPC175x_6x \-Wa,-alhms=./out/main.lst \-o ./out/main.o "src/main.cpp"./out/arm-gcc.elf: ./out/startup_lpc17xx.o ./src/LPC1768.ld ./out/main.oarm-none-eabi-gcc \-T ./src/LPC1768.ld \-mcpu=cortex-m3 -mthumb -mthumb-interwork -Wl,-Map="./out/arm-gcc.map" -nostartfiles \-o "./out/arm-gcc.elf" "./out/startup_lpc17xx.o" "./out/main.o"arm-none-eabi-objcopy -O ihex ./out/arm-gcc.elf ./out/arm-gcc.hex@echo ----------------------------------------@echo after build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------

makefile v0.5

# @file makefile
# @brief 从build.bat进化出来的makefile
#	v0.5 将编译选项定义为变量
#	v0.4 确认和验证是否实际目标可以写成伪目标, 答案是不能(会失去文件自动检测编译的功能,导致全部编译)
#	v0.3 声明伪目标, 加入编译目标 rebuild
#	v0.2 加入编译目标的依赖,提高编译效率
#	v0.1 最简单的makefile, 从.bat直接改过来# makefile_obj : depend(可选)
#	action
# makefile_obj从行首开始
# action必须从TAB键开始
# 命令之前加@, 就关掉了echo回显# 如果多个编译目标的规则都相同,可以将多个目标放在一起,用空格分开
# e.g. 
# obj1 obj2: main.cpp
# gcc -xx ...# 在编译目标的gcc命令中使用的自动变量
# @$ 当前目标
# @< 依赖的第一个文件
# -o @$ @< # 要编译的文件比较多时, 可以代替硬编码# c_file: src/*.c
# 如果编译目标指定的依赖不存在,makefile会报错
# 如果没有的实际目标,就不要留在makefile中# 编译具体目标时, 不能写成伪目标,而是要直接写成真正要编译的.o目标,否则就不能检测依赖的文件变化了,而是每次都全部编译ASM_FLAGS = -mcpu=cortex-m3 -mthumb --gdwarf-2 -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \--defsym __UVISION_VERSION=543 \--defsym __GCC=1 \--defsym __GCC_VERSION=1431 \--defsym LPC175x_6x=1CPP_FLAGS = -mcpu=cortex-m3 -mthumb -gdwarf-2 -MMD -pedantic -O0 -mapcs-frame -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \-D__UVISION_VERSION="543" \-D__GCC -D__GCC_VERSION="1431" \-DLPC175x_6xLINK_FLAGS = -mcpu=cortex-m3 -mthumb -mthumb-interwork -nostartfiles.PHONY: all clean rebuildall: \./out/arm-gcc.elf@echo build allrebuild:make cleanmakeclean:@cls@if not exist ".\out" mkdir ".\out"@if exist ".\out\*" del /q ".\out\*"@echo ----------------------------------------@echo before build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------./out/startup_lpc17xx.o: src/startup_lpc17xx.sarm-none-eabi-as \$(ASM_FLAGS) \-alhms=./out/startup_lpc17xx.lst \--MD ./out/startup_lpc17xx.d \-o ./out/startup_lpc17xx.o "src/startup_LPC17xx.s"./out/main.o: src/main.cpparm-none-eabi-gcc \-c \$(CPP_FLAGS) \-Wa,-alhms=./out/main.lst \-o ./out/main.o "src/main.cpp"./out/arm-gcc.elf: ./out/startup_lpc17xx.o ./src/LPC1768.ld ./out/main.oarm-none-eabi-gcc \$(LINK_FLAGS) \-Wl,-Map="./out/arm-gcc.map" \-T ./src/LPC1768.ld \-o "./out/arm-gcc.elf" "./out/startup_lpc17xx.o" "./out/main.o"arm-none-eabi-objcopy -O ihex ./out/arm-gcc.elf ./out/arm-gcc.hex@echo ----------------------------------------@echo after build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------

makefile v0.6

# @file makefile
# @brief 从build.bat进化出来的makefile
#	v0.6 用makefil自动变量优化编译命令, 使gcc命令行更灵活
#	v0.5 将编译选项定义为变量
#	v0.4 确认和验证是否实际目标可以写成伪目标, 答案是不能(会失去文件自动检测编译的功能,导致全部编译)
#	v0.3 声明伪目标, 加入编译目标 rebuild
#	v0.2 加入编译目标的依赖,提高编译效率
#	v0.1 最简单的makefile, 从.bat直接改过来# makefile_obj : depend(可选)
#	action
# makefile_obj从行首开始
# action必须从TAB键开始
# 命令之前加@, 就关掉了echo回显# 如果多个编译目标的规则都相同,可以将多个目标放在一起,用空格分开
# e.g. 
# obj1 obj2: main.cpp
# gcc -xx ...# 在编译目标的gcc命令中使用的自动变量
# @$ 当前目标
# @< 依赖的第一个文件
# -o @$ @< # 要编译的文件比较多时, 可以代替硬编码# c_file: src/*.c
# 如果编译目标指定的依赖不存在,makefile会报错
# 如果没有的实际目标,就不要留在makefile中# 编译具体目标时, 不能写成伪目标,而是要直接写成真正要编译的.o目标,否则就不能检测依赖的文件变化了,而是每次都全部编译ASM_FLAGS = -mcpu=cortex-m3 -mthumb --gdwarf-2 -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \--defsym __UVISION_VERSION=543 \--defsym __GCC=1 \--defsym __GCC_VERSION=1431 \--defsym LPC175x_6x=1CPP_FLAGS = -mcpu=cortex-m3 -mthumb -gdwarf-2 -MMD -pedantic -O0 -mapcs-frame -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \-D__UVISION_VERSION="543" \-D__GCC -D__GCC_VERSION="1431" \-DLPC175x_6xLINK_FLAGS = -mcpu=cortex-m3 -mthumb -mthumb-interwork -nostartfiles.PHONY: all clean rebuildall: \./out/arm-gcc.elf@echo build allrebuild:make cleanmakeclean:@cls@if not exist ".\out" mkdir ".\out"@if exist ".\out\*" del /q ".\out\*"@echo ----------------------------------------@echo before build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------./out/startup_lpc17xx.o: src/startup_lpc17xx.sarm-none-eabi-as \$(ASM_FLAGS) \-alhms=$(patsubst %.o,%.lst,$@) \--MD $(patsubst %.o,%.d,$@) \-o $@ $<./out/main.o: src/main.cpparm-none-eabi-gcc \-c \$(CPP_FLAGS) \-Wa,-alhms="$(patsubst %.o,%.lst,$@)" \-o $@ $<./out/arm-gcc.elf: ./src/LPC1768.ld ./out/startup_lpc17xx.o ./out/main.oarm-none-eabi-gcc \$(LINK_FLAGS) \-Wl,-Map="$(patsubst %.elf,%.map,$@)" \-T $< \-o $@ $(filter-out $<, $^)arm-none-eabi-objcopy -O ihex $@ $(patsubst .elf,.hex,$@)@echo ----------------------------------------@echo after build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------

makefile v0.7

# @file makefile
# @brief 从build.bat进化出来的makefile
#	v0.7 在make命令中加注释,解释用到的make内置函数的功能和用法
#	v0.6 用makefil自动变量优化编译命令, 使gcc命令行更灵活
#	v0.5 将编译选项定义为变量
#	v0.4 确认和验证是否实际目标可以写成伪目标, 答案是不能(会失去文件自动检测编译的功能,导致全部编译)
#	v0.3 声明伪目标, 加入编译目标 rebuild
#	v0.2 加入编译目标的依赖,提高编译效率
#	v0.1 最简单的makefile, 从.bat直接改过来# makefile_obj : depend(可选)
#	action
# makefile_obj从行首开始
# action必须从TAB键开始
# 命令之前加@, 就关掉了echo回显# 如果多个编译目标的规则都相同,可以将多个目标放在一起,用空格分开
# e.g. 
# obj1 obj2: main.cpp
# gcc -xx ...# 在编译目标的gcc命令中使用的自动变量
# @$ 当前目标
# @< 依赖的第一个文件
# -o @$ @< # 要编译的文件比较多时, 可以代替硬编码# c_file: src/*.c
# 如果编译目标指定的依赖不存在,makefile会报错
# 如果没有的实际目标,就不要留在makefile中# 编译具体目标时, 不能写成伪目标,而是要直接写成真正要编译的.o目标,否则就不能检测依赖的文件变化了,而是每次都全部编译ASM_FLAGS = -mcpu=cortex-m3 -mthumb --gdwarf-2 -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \--defsym __UVISION_VERSION=543 \--defsym __GCC=1 \--defsym __GCC_VERSION=1431 \--defsym LPC175x_6x=1CPP_FLAGS = -mcpu=cortex-m3 -mthumb -gdwarf-2 -MMD -pedantic -O0 -mapcs-frame -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \-D__UVISION_VERSION="543" \-D__GCC -D__GCC_VERSION="1431" \-DLPC175x_6xLINK_FLAGS = -mcpu=cortex-m3 -mthumb -mthumb-interwork -nostartfiles.PHONY: all clean rebuildall: \./out/arm-gcc.elf# 在make目标中, 可以加注释, 但是注释必须顶着行头写@echo build allrebuild:make cleanmakeclean:@cls@if not exist ".\out" mkdir ".\out"@if exist ".\out\*" del /q ".\out\*"@echo ----------------------------------------@echo before build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------./out/startup_lpc17xx.o: src/startup_lpc17xx.s
# patsubst 是make内置函数, 格式 patsubst %1,%2,%3
# 作用 : 将%3的内容中的%1字符串换为%2字符串arm-none-eabi-as \$(ASM_FLAGS) \-alhms=$(patsubst %.o,%.lst,$@) \--MD $(patsubst %.o,%.d,$@) \-o $@ $<# $@ 是编译目标的名字
# $< 是依赖的第一个内容./out/main.o: src/main.cpparm-none-eabi-gcc \-c \$(CPP_FLAGS) \-Wa,-alhms="$(patsubst %.o,%.lst,$@)" \-o $@ $<./out/arm-gcc.elf: ./src/LPC1768.ld ./out/startup_lpc17xx.o ./out/main.oarm-none-eabi-gcc \$(LINK_FLAGS) \-Wl,-Map="$(patsubst %.elf,%.map,$@)" \-T $< \-o $@ $(filter-out $<, $^)# filter-out %1,%2
# filter-out 是将%2中的%1去掉arm-none-eabi-objcopy -O ihex $@ $(patsubst .elf,.hex,$@)@echo ----------------------------------------@echo after build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------

makefile v0.8

# @file makefile
# @brief 从build.bat进化出来的makefile
#	v0.8 用通配符来简化文件的编译(不用写具体的目标文件和依赖文件的名字了),这样对于大工程,makefile就不用写的很复杂
#	v0.7 在make命令中加注释,解释用到的make内置函数的功能和用法
#	v0.6 用makefil自动变量优化编译命令, 使gcc命令行更灵活
#	v0.5 将编译选项定义为变量
#	v0.4 确认和验证是否实际目标可以写成伪目标, 答案是不能(会失去文件自动检测编译的功能,导致全部编译)
#	v0.3 声明伪目标, 加入编译目标 rebuild
#	v0.2 加入编译目标的依赖,提高编译效率
#	v0.1 最简单的makefile, 从.bat直接改过来# makefile_obj : depend(可选)
#	action
# makefile_obj从行首开始
# action必须从TAB键开始
# 命令之前加@, 就关掉了echo回显# 如果多个编译目标的规则都相同,可以将多个目标放在一起,用空格分开
# e.g. 
# obj1 obj2: main.cpp
# gcc -xx ...# 在编译目标的gcc命令中使用的自动变量
# @$ 当前目标
# @< 依赖的第一个文件
# -o @$ @< # 要编译的文件比较多时, 可以代替硬编码# c_file: src/*.c
# 如果编译目标指定的依赖不存在,makefile会报错
# 如果没有的实际目标,就不要留在makefile中# 编译具体目标时, 不能写成伪目标,而是要直接写成真正要编译的.o目标,否则就不能检测依赖的文件变化了,而是每次都全部编译ASM_FLAGS = -mcpu=cortex-m3 -mthumb --gdwarf-2 -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \--defsym __UVISION_VERSION=543 \--defsym __GCC=1 \--defsym __GCC_VERSION=1431 \--defsym LPC175x_6x=1CPP_FLAGS = -mcpu=cortex-m3 -mthumb -gdwarf-2 -MMD -pedantic -O0 -mapcs-frame -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \-D__UVISION_VERSION="543" \-D__GCC -D__GCC_VERSION="1431" \-DLPC175x_6xLINK_FLAGS = -mcpu=cortex-m3 -mthumb -mthumb-interwork -nostartfiles.PHONY: all clean rebuildall: \./out/arm-gcc.elf# 在make目标中, 可以加注释, 但是注释必须顶着行头写@echo build allrebuild:make cleanmakeclean:@cls@if not exist ".\out" mkdir ".\out"@if exist ".\out\*" del /q ".\out\*"@echo ----------------------------------------@echo before build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------./out/startup_lpc17xx.o: src/startup_lpc17xx.s
# patsubst 是make内置函数, 格式 patsubst %1,%2,%3
# 作用 : 将%3的内容中的%1字符串换为%2字符串arm-none-eabi-as \$(ASM_FLAGS) \-alhms=$(patsubst %.o,%.lst,$@) \--MD $(patsubst %.o,%.d,$@) \-o $@ $<# $@ 是编译目标的名字
# $< 是依赖的第一个内容# 如果要使用通配符, 估计得将.o生成到不同输出目录才行,否则命令目标有冲突
# e.g. *.cpp 生成到 out/cpp, *.c 生成到out/c
./out/%.o: src/%.cpparm-none-eabi-gcc \-c \$(CPP_FLAGS) \-Wa,-alhms="$(patsubst %.o,%.lst,$@)" \-o $@ $<./out/arm-gcc.elf: ./src/LPC1768.ld ./out/startup_lpc17xx.o ./out/main.oarm-none-eabi-gcc \$(LINK_FLAGS) \-Wl,-Map="$(patsubst %.elf,%.map,$@)" \-T $< \-o $@ $(filter-out $<, $^)# filter-out %1,%2
# filter-out 是将%2中的%1去掉arm-none-eabi-objcopy -O ihex $@ $(patsubst .elf,.hex,$@)@echo ----------------------------------------@echo after build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------

makefile v0.9

arm-none-eabi-objcopy 语句的字符替换手误,修正了。

# @file makefile
# @brief 从build.bat进化出来的makefile
#	v0.9 在每个gcc命令之间加分隔行(容易看清楚每个命令的区间)
#	v0.8 用通配符来简化文件的编译(不用写具体的目标文件和依赖文件的名字了),这样对于大工程,makefile就不用写的很复杂
#	v0.7 在make命令中加注释,解释用到的make内置函数的功能和用法
#	v0.6 用makefil自动变量优化编译命令, 使gcc命令行更灵活
#	v0.5 将编译选项定义为变量
#	v0.4 确认和验证是否实际目标可以写成伪目标, 答案是不能(会失去文件自动检测编译的功能,导致全部编译)
#	v0.3 声明伪目标, 加入编译目标 rebuild
#	v0.2 加入编译目标的依赖,提高编译效率
#	v0.1 最简单的makefile, 从.bat直接改过来# makefile_obj : depend(可选)
#	action
# makefile_obj从行首开始
# action必须从TAB键开始
# 命令之前加@, 就关掉了echo回显# 如果多个编译目标的规则都相同,可以将多个目标放在一起,用空格分开
# e.g. 
# obj1 obj2: main.cpp
# gcc -xx ...# 在编译目标的gcc命令中使用的自动变量
# @$ 当前目标
# @< 依赖的第一个文件
# -o @$ @< # 要编译的文件比较多时, 可以代替硬编码# c_file: src/*.c
# 如果编译目标指定的依赖不存在,makefile会报错
# 如果没有的实际目标,就不要留在makefile中# 编译具体目标时, 不能写成伪目标,而是要直接写成真正要编译的.o目标,否则就不能检测依赖的文件变化了,而是每次都全部编译ASM_FLAGS = -mcpu=cortex-m3 -mthumb --gdwarf-2 -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \--defsym __UVISION_VERSION=543 \--defsym __GCC=1 \--defsym __GCC_VERSION=1431 \--defsym LPC175x_6x=1CPP_FLAGS = -mcpu=cortex-m3 -mthumb -gdwarf-2 -MMD -pedantic -O0 -mapcs-frame -mthumb-interwork \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" \-I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" \-D__UVISION_VERSION="543" \-D__GCC -D__GCC_VERSION="1431" \-DLPC175x_6xLINK_FLAGS = -mcpu=cortex-m3 -mthumb -mthumb-interwork -nostartfiles.PHONY: all clean rebuildall: \./out/arm-gcc.elf# 在make目标中, 可以加注释, 但是注释必须顶着行头写@echo build allrebuild:make cleanmakeclean:@cls@if not exist ".\out" mkdir ".\out"@if exist ".\out\*" del /q ".\out\*"@echo ----------------------------------------@echo before build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------./out/startup_lpc17xx.o: src/startup_lpc17xx.s
# patsubst 是make内置函数, 格式 patsubst %1,%2,%3
# 作用 : 将%3的内容中的%1字符串换为%2字符串arm-none-eabi-as \$(ASM_FLAGS) \-alhms=$(patsubst %.o,%.lst,$@) \--MD $(patsubst %.o,%.d,$@) \-o $@ $<@echo ----------# $@ 是编译目标的名字
# $< 是依赖的第一个内容# 如果要使用通配符, 估计得将.o生成到不同输出目录才行,否则命令目标有冲突
# e.g. *.cpp 生成到 out/cpp, *.c 生成到out/c
./out/%.o: src/%.cpparm-none-eabi-gcc \-c \$(CPP_FLAGS) \-Wa,-alhms="$(patsubst %.o,%.lst,$@)" \-o $@ $<@echo ----------./out/arm-gcc.elf: ./src/LPC1768.ld ./out/startup_lpc17xx.o ./out/main.oarm-none-eabi-gcc \$(LINK_FLAGS) \-Wl,-Map="$(patsubst %.elf,%.map,$@)" \-T $< \-o $@ $(filter-out $<, $^)@echo ----------# filter-out %1,%2
# filter-out 是将%2中的%1去掉arm-none-eabi-objcopy -O ihex $@ $(patsubst %.elf,%.hex,$@)@echo ----------@echo ----------------------------------------@echo after build@echo ----------------------------------------@dir /s /b /oneg@echo ----------------------------------------

最终编译效果

----------------------------------------
before build
----------------------------------------
D:\my_dev\my_test\arm-gcc-makefile\v0.8\doc
D:\my_dev\my_test\arm-gcc-makefile\v0.8\makefile
D:\my_dev\my_test\arm-gcc-makefile\v0.8\out
D:\my_dev\my_test\arm-gcc-makefile\v0.8\src
D:\my_dev\my_test\arm-gcc-makefile\v0.8\doc\build.bat
D:\my_dev\my_test\arm-gcc-makefile\v0.8\src\LPC1768.ld
D:\my_dev\my_test\arm-gcc-makefile\v0.8\src\main.cpp
D:\my_dev\my_test\arm-gcc-makefile\v0.8\src\startup_LPC17xx.s
----------------------------------------
make[1]: Leaving directory `D:/my_dev/my_test/arm-gcc-makefile/v0.8'
make
make[1]: Entering directory `D:/my_dev/my_test/arm-gcc-makefile/v0.8'
arm-none-eabi-as \-mcpu=cortex-m3 -mthumb --gdwarf-2 -mthumb-interwork -I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" -I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" -I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" -I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" --defsym __UVISION_VERSION=543 --defsym __GCC=1 --defsym __GCC_VERSION=1431 --defsym LPC175x_6x=1 \-alhms=out/startup_lpc17xx.lst \--MD out/startup_lpc17xx.d \-o out/startup_lpc17xx.o src/startup_lpc17xx.s
----------
arm-none-eabi-gcc \-c \-mcpu=cortex-m3 -mthumb -gdwarf-2 -MMD -pedantic -O0 -mapcs-frame -mthumb-interwork -I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include" -I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/lib/gcc/arm-none-eabi/14.3.1/include" -I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1" -I"D:/Arm GNU Toolchain arm-none-eabi/14.3 rel1/arm-none-eabi/include/c++/14.3.1/arm-none-eabi" -D__UVISION_VERSION="543" -D__GCC -D__GCC_VERSION="1431" -DLPC175x_6x \-Wa,-alhms="out/main.lst" \-o out/main.o src/main.cpp
----------
arm-none-eabi-gcc \-mcpu=cortex-m3 -mthumb -mthumb-interwork -nostartfiles \-Wl,-Map="out/arm-gcc.map" \-T src/LPC1768.ld \-o out/arm-gcc.elf out/startup_lpc17xx.o out/main.o
----------
arm-none-eabi-objcopy -O ihex out/arm-gcc.elf out/arm-gcc.elf
----------
----------------------------------------
after build
----------------------------------------
D:\my_dev\my_test\arm-gcc-makefile\v0.8\doc
D:\my_dev\my_test\arm-gcc-makefile\v0.8\makefile
D:\my_dev\my_test\arm-gcc-makefile\v0.8\out
D:\my_dev\my_test\arm-gcc-makefile\v0.8\src
D:\my_dev\my_test\arm-gcc-makefile\v0.8\doc\build.bat
D:\my_dev\my_test\arm-gcc-makefile\v0.8\out\arm-gcc.elf
D:\my_dev\my_test\arm-gcc-makefile\v0.8\out\arm-gcc.map
D:\my_dev\my_test\arm-gcc-makefile\v0.8\out\main.d
D:\my_dev\my_test\arm-gcc-makefile\v0.8\out\main.lst
D:\my_dev\my_test\arm-gcc-makefile\v0.8\out\main.o
D:\my_dev\my_test\arm-gcc-makefile\v0.8\out\startup_lpc17xx.d
D:\my_dev\my_test\arm-gcc-makefile\v0.8\out\startup_lpc17xx.lst
D:\my_dev\my_test\arm-gcc-makefile\v0.8\out\startup_lpc17xx.o
D:\my_dev\my_test\arm-gcc-makefile\v0.8\src\LPC1768.ld
D:\my_dev\my_test\arm-gcc-makefile\v0.8\src\main.cpp
D:\my_dev\my_test\arm-gcc-makefile\v0.8\src\startup_LPC17xx.s
----------------------------------------
build all
make[1]: Leaving directory `D:/my_dev/my_test/arm-gcc-makefile/v0.8'D:\my_dev\my_test\arm-gcc-makefile\v0.8>

备注

如果是一个复杂点的工程,可能需要多个.mk才方便编译。
可以用make -c 去到一个子目录中(那里有子模块的.mk), 编译完sub.mk, 再回到主make中。
逐个子模块的.mk都编译完。再执行link.
可以参考开源工程(e.g. Smoothieware)

备注

gnu官方的make手册(https://www.gnu.org/software/make/manual/), 有makefile编写的细节问题,可以去看下。

备注

makefile命令行写的灵活一些,方便扩展到其他工程用,不过也别太过了,毕竟不是经常玩makefile.
makefile优化差不多就行,免得自己以后(e.g. 1年以后?)看时,看不懂就坏了。

END

http://www.dtcms.com/a/491452.html

相关文章:

  • 郑州外贸网站建设商家内网网站开发报价
  • xxl-job pg数据库适配
  • OSPF路由协议重点总结
  • QT6中QToolBox功能与应用
  • Linux 进程信号机制详解
  • 淘宝客做网站推广自定义页面wordpress
  • YOLO-V1 与 YOLO-V2
  • 中科大少年班记(2025年10月)
  • 微信公众号端网站开发小程序开发费用一览表fhq华网天下
  • 体育数据库:搭建体育应用的核心「数据引擎」
  • 【JETSON+FPGA+GMSL】多功能图像采集卡,以高集成、多通道方案应对工业视觉挑战
  • 做网站教学书微信公众号下载安装
  • 【从零开始构建性能测试体系-07】理解响应时间、吞吐量与并发:性能测试关键指标解读
  • C/C++字符串
  • 上网站乱码python网站开发效率
  • 告别“搬砖”:在AI的辅助下,前端如何触及业务与架构的深水区?
  • 大显存 AI 训练实战:PyTorch/TensorFlow 参数调试与多场景落地指南
  • 石狮新站seo电子商务网站建设与管理感想
  • Socket 抓包工具与实战,从抓取到定位(Socket 的命令、分析)
  • 让安全驾驶有“AI”相伴|腾视科技DMS视频监控一体机,守护每一次出行
  • 软考高项论文考试攻略1:从趋势分析到实战技巧
  • C语言:自定义类型
  • MATLAB中双馈发电机与无刷双馈发电机低电压穿越的异同分析
  • 做公司网站需要多南京建设行政主管部门网站
  • 【CDA案例】某女装品牌如何用AARRR 模型落地实践使私域增长突围的?5分钟get到​重点
  • 企业电话交换机配置在线聊天功能安装文档
  • 公司做网站需要什么条件程序员培训机构出来找工作好找吗
  • Python3编程之Python基础(更新中...)
  • 从概念到实战:一文读懂实时操作系统(RTOS),并洞悉其与Linux/Windows的本质区别
  • 网站建设谈单思路互联网保险的特点不包括