开发辅助工具
shell
调试
1)使用trap命令shell脚本执行时会产生三个所谓的伪信号,可以使用trap命令捕获这三个“伪信号”,并输出相关的调试信息
信号名 | 产生原因 |
---|---|
EXIT | 从一个函数中退出或整个脚本执行完毕 |
ERROR | 从一条命令返回非零状态时(代表命令执行不成功) |
DEBUG | 脚本中每一条命令执行之前 |
trap示例:
#! /bin/bash
ERRTRAP()
{
echo "[LINE:$1] Error: exited with status $?"
}
test()
{
return 1;
}
trap 'ERRTRAP $LINENO' ERR
hhh
test
2)使用tee命令
在shell脚本中管道以及输入输出重定向使用得非常多,在管道的作用下,一些命令的执行结果直接成为了下一条命令的输入。
如果执行中出现了问题,此时我们就可以借助于tee命令了。
tee命令会从标准输入读取数据,将其内容输出到标准输出设备,同时又可将内容保存成文件
tee使用示例:
#! /bin/bash
ipaddr=`sbin/ifconfig | grep 'inet addr:' | grep -v '127.0.0.1' | tee temp.txt | cut -d : -f3 | awk '{print $1]'`
echo $ipaddr
3)使用“调试钩子”
在C语言程序中,我们经常使用DEBUG宏来控制是否要输出调试信息,
在shell脚本中我们同样可以使用这样的机制,如下列代码所示:
if [ “$DEBUG” = “true” ]; then
echo “debugging” #此处可以输出调试信息
fi
这样的代码块通常称之为“调试钩子”或“调试块”。
在调试钩子内部可以输出任何您想输出的调试信息,使用调试钩子的好处是它是可以通过DEBUG变量来控制的,
在脚本的开发调试阶段,可以先执行export DEBUG=true命令打开调试钩子,使其输出调试信息,
而在把脚本交付使用时可以先执行export DEBUG=false,也无需再费事把脚本中的调试语句一一删除。
hook使用示例:
#! /bin/bash
TRACE()
{
if [ "$DEBUG" = "true" ]; then
$@
fi
}
a=1
TRACE echo "a=$a"
if [ "$a" -eq 1 ]
then
b=2
else
b=1
fi
c=3
TRACE echo "c=$c"
4)shell的执行选项
-n 只读取shell脚本,但不实际执行
-x 进入跟踪方式,显示所执行的每一条命令
-c "string" 从strings中读取命令
$LINENO:代表shell脚本的当前行号,类似于C语言中的内置宏__LINE__
$FUNCNAME:函数的名字,类似于C语言中的内置宏__func__,但宏__func__只能代表当前所在的函数名,
而$FUNCNAME的功能更强大,它是一个数组变量,其中包含了整个调用链上所有的函数的名字,
故变量${FUNCNAME[0]}代表shell脚本当前正在执行的函数的名字,
而变量${FUNCNAME[1]}则代表调用函数${FUNCNAME[0]}的函数的名字,余者可以依此类推。
$PS4:$PS4的值将被显示在“-x”选项输出的每一条命令的前面。
在Bash Shell中,缺省的$PS4的值是"+"号。
如先执行export PS4='+{$LINENO:${FUNCNAME[0]}} ', 然后再使用“-x”选项来执行脚本,
就能在每一条实际执行的命令前面显示其行号以及所属的函数名。
git
常用命令
-
拉取常用
git pull git rebase --abort
-
本地常用
git add (-u) * git checkout -- git commit (--amend -s) git reset --soft HEAD^ git reset --hard (commit_id) git stash git stash pop git diff git clean -df git log git reflog
-
提交常用
git push xx HEAD:refs/for/xxx
-
分支常用
git checkout branch_name git branch git branch -D git branch -a git branch -vv
error解决
-
email address xxx is not registered in your account
可能原因1.git账户配置不对配置git账户 git config --global user.name git config user.name git config --global user.email 或通过修改git配置文件 /etc/gitconfig:适用于所有用户和所有项目的值 ~/.gitconfig:只适用于当前登录用户的配置 .git/config:该git项目的配置 git config user.email git commit --amend --reset-author
可能原因2.ssh登录账户不对
修改.git/config中的对应配置项
makefile
常用命令
重定向:
make >filename 2>&1
编译中的.d依赖:
-M的选项:自动寻找源文件中包含的头文件,并生成一个依赖关系
-MM:生成文件的依赖关系,和-M 类似,但不包含标准库的头文件
-MG:要求把缺失的头文件按存在对待,并且假定他们和源程序文件在同一目录下,必须和-M选项一起用
-MF File:当使用了-M或者-MM选项时,则把依赖关系写入名为File的文件中。
-MD:等同于-M -MF File,但是默认关闭了-E选项。其输出的文件名是基于-o 选项,
若给定-o选项,则输出的文件名是-o指定的文件名,并添加.d后缀,
若没有给定,则输入的文件名作为输出的文件名,并添加.d后缀
.d依赖示例:
#include "stdio.h"
#include "defs.h"
int main(int argc, char *argv[])
{
printf("Hello, %s!\n", NAME);
return 0;
}
==========================================
命令:
gcc -M main.c
输出:
main.o: main.c defs.h \
/usr/include/stdio.h \
/usr/include/features.h \
/usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \
...
==========================================
命令:
gcc -MM main.c
输出:
main.o: main.c defs.h
函数
call函数:
1)唯一一个可以创建定制化参数函数的引用函数。
2)支持将一个变量定义为一个复杂的表达式,用call函数根据不同的参数对它进行展开来获取不同的结果
语法:
$(call VARIABLE,PARAM,PARAM,...)
参数:
在执行时,将它的参数"PARAM"依次赋给临时变量"$(1)","$(2)"
call对参数的数目没有限制,也可以没有参数值
最后再对VARIABLE展开后的表达式进行处理.
返回值:
VARIABLE展开后的表达式的值
call函数示例:
define FUNC1
$(info echo 4-$(1) $(2))
endef
$(call FUNC1,hello,wolrd)
all:
@echo Done
变量
MAKEFILE_LIST:
$(lastword $(MAKEFILE_LIST)):用于获取当前路径
--Q: 为什么不用 $(shell pwd)
--A: 可以返回当前路径,但当makefile中存在make -f newMakefile,使用$(shell pwd)返回的就不是当前路径
伪目标
默认情况下:
1)make认为目标对应着一个文件
2)make比较目标文件和依赖文件的新旧关系,决定是否执行命令
3)make以文件处理作为第一优先级
伪目标:
1)通过.PHONY关键字声明一个伪目标
2)伪目标不对应任何实际的文件
3)不管伪目标的依赖是否更新,命令总是执行
4)伪目标的语法:先声明,后使用
5)伪目标的本质:是make中特殊目标.PHONY的依赖
6)当一个目标的依赖包含伪目标时,伪目标定义的命令总会被执行
7)规则调用(使用伪目标来模拟C语言中的函数调用)
伪目标示例1:
====================================
hello.out : func.o main.o
gcc -o hello.out func.o main.o
func.o : func.c
gcc -o func.o -c func.c
main.o : main.c
gcc -o main.o -c main.c
.PHONY : clean rebuild all
rebuild : clean all
all : hello.out
clean :
rm *.o hello.out
====================================
执行:
make all
输出:
gcc -o func.o -c func.c
gcc -o main.o -c main.c
gcc -o hello.out func.o main.o
-------------------------------------
执行:
make rebuild
输出:
rm *.o hello.out
gcc -o func.o -c func.c
gcc -o main.o -c main.c
gcc -o hello.out func.o main.o
绕开.PHONY关键字定义伪目标:
如果一个规则没有命令或则依赖,并且它的目标不是一个存在的文件名,在执行此规则时,目标总会被认为是最新的
伪目标示例2:
hello.out : func.o main.o
gcc -o hello.out func.o main.o
func.o : func.c
gcc -o func.o -c func.c
main.o : main.c
gcc -o main.o -c main.c
clean : FORCE
rm *.o hello.out
FORCE :
传值
make VALUE=val
递归
make -c xxx/makefile
-include xxx/makefile
条件判断
ifeq( $(a)_$(b), y_y )
endif
实现逻辑与: " a=y && b=y "
CMake
常用命令
常见变量
CMAKE_AR: 静态库的归档工具的名称
CMAKE_ARGC: 在脚本模式下传给CMake的命令行参数的个数。当运行在-P脚本模式下,CMake设置该变量为命令行参数的个数。
CMAKE_ARGV0: 在脚本模式下传给CMake的命令行的第一个参数。
CMAKE_BINARY_DIR: 构建树的最外层路径,是当前CMake构建树的最外层的全路径。
对于在源码中构建的情况,它与CMAKE_SOURCE_DIR的值一样。
CMAKE_BUILD_TOOL: 执行构建过程的工具。该变量设置为CMake构建时输出所需的程序。
对于VS 6,CMAKE_BUILD_TOOL设置为msdev,对于Unix,它被设置为make或 gmake。
对于VS 7,它被设置为devenv.。对于Nmake构建文件,它的值为nmake。
CMAKE_CACHEFILE_DIR: 该变量设置为包含CMakeCache.txt文件的目录的全路径。通常与CMAKE_BINARY_DIR的值一样。
CMAKE_CACHE_MAJOR_VERSION: 用于创建CMakeCache.txt文件的CMake的主版本号。只有当CMake运行于在由一个不同版本的CMake创建的cache文件时,这个变量的值才会不同。
CMAKE_CACHE_MINOR_VERSION: 用于创建CMakeCache.txt文件的CMake的次版本号。只有当CMake运行于在由一个不同版本的CMake创建的cache文件时,这个变量的值才会不同。
CMAKE_COMMAND: 指向cmake可执行程序的全路径。
CMAKE_CURRENT_BINARY_DIR: 当前正在处理的构建目录。每个由add_subdirectory添加的目录将会在构建树中创建一个构建目录。对于直接在源码目录中编译的情况,当前正在处理的构建目录就是当前源码所在的目录。
CMAKE_CURRENT_LIST_DIR: 当前处理的CMakeLists.txt文件所在的目录。
CMAKE_CURRENT_LIST_FILE: 当前处理的CMakeLists.txt文件的全路径。
CMAKE_CURRENT_LIST_LINE: 当前处理的CMakeLists.txt文件的行号。
CMAKE_CURRENT_SOURCE_DIR: 当前处理的源码路径。
CMAKE_EXECUTABLE_SUFFIX: 该平台上可执行程序的后缀。
CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES: 共享库额外的后缀名。
这些共享库不是CMAKE_SHARED_LIBRARY_SUFFIX。
在分析某个目标链接的库时,CMake使用该变量识别外部共享库文件。
CMAKE_HOME_DIRECTORY: 源码树的顶级目录的路径。
CMAKE_IMPORT_LIBRARY_PREFIX: 链接的引入库的前缀。CMAKE_IMPORT_LIBRARY_PREFIX_<LANG> overrides this for language <LANG>.
CMAKE_IMPORT_LIBRARY_SUFFIX: 链接的引入库的后缀。CMAKE_IMPORT_LIBRARY_SUFFIX_<LANG> overrides this for language <LANG>.
CMAKE_LINK_LIBRARY_SUFFIX: 链接的库的后缀。如Windows下是.lib。
CMAKE_MAJOR_VERSION: CMake的主版本号。
CMAKE_MINOR_VERSION: CMake的次版本号。
CMAKE_PARENT_LIST_FILE: 正在处理的CMakeLists.txt文件的父CMakelists.txt文件所在的路径。
CMAKE_PROJECT_NAME: 当前工程的名字。
CMAKE_ROOT: cmake的安装目录。
CMAKE_SCRIPT_MODE_FILE: 脚本模式下正在处理的脚本文件。
CMAKE_SHARED_LIBRARY_PREFIX: 链接的共享库的前缀。TCMAKE_SHARED_LIBRARY_PREFIX_<LANG> overrides this for language <LANG>.
CMAKE_SHARED_LIBRARY_SUFFIX:链接的共享库的后缀。CMAKE_SHARED_LIBRARY_SUFFIX_<LANG> overrides this for language <LANG>.
CMAKE_SHARED_MODULE_PREFIX: 链接的可加载模块的前缀。CMAKE_SHARED_MODULE_PREFIX_<LANG> overrides this for language <LANG>.
CMAKE_SHARED_MODULE_SUFFIX: 链接的可加载模块的后缀。CMAKE_SHARED_MODULE_SUFFIX_<LANG> overrides this for language <LANG>.
CMAKE_SIZEOF_VOID_P: void指针的大小。
CMAKE_SOURCE_DIR: 源码树的最顶级目录。当在源码中编译时,与CMAKE_BINARY_DIR的值一致。
CMAKE_STANDARD_LIBRARIES: 链接到每个可执行程序和共享库的标准库。它包含一系列库。
CMAKE_STATIC_LIBRARY_PREFIX:链接的静态库的前缀。CMAKE_STATIC_LIBRARY_PREFIX_<LANG> overrides this for language <LANG>.
CMAKE_STATIC_LIBRARY_SUFFIX: 链接的静态库的后缀。CMAKE_STATIC_LIBRARY_SUFFIX_<LANG> overrides this for language <LANG>.
CMAKE_VERSION: CMake的完全版本号。格式:major.minor.patch[.tweak[-id]]。
PROJECT_BINARY_DIR: 工程的构建目录。
PROJECT_NAME: 工程名。
PROJECT_SOURCE_DIR: 当前工程的顶级目录。
[Project name]_BINARY_DIR: 对应工程的顶级构建目录。
[Project name]_SOURCE_DIR: 对应工程的源码目录。
CMAKE_SYSTEM_NAME: 目标机target所在的操作系统名称,只有当CMAKE_SYSTEM_NAME这个变量被设置了,CMake才认为此时正在交叉编译,它会额外设置一个变量CMAKE_CROSSCOMPILING为TRUE.
CMAKE_CROSSCOMPILING: 当前CMake是否是交叉编译。
CMAKE_C_COMPILER: C语言编译器,这里可以将变量设置成完整路径或者文件名,
设置成完整路径时CMake会去这个路径下去寻找编译相关的其他工具比如linker,binutils等,
如果写的文件名带有arm-elf等等前缀,CMake会识别到并且去寻找相关的交叉编译器。
CMAKE_CXX_COMPILER: 同上,此时代表的是C++编译器。
CMAKE_FIND_ROOT_PATH: 代表了一系列的相关文件夹路径的根路径的变更,如设置了/opt/arm/,所有的Find_xxx.cmake都会优先根据这个路径下的/usr/lib,/lib等进行查找,然后才会去用户自己的/usr/lib和/lib进行查找,如果有一些库是不被包含在/opt/arm里面的,也可以显示指定多个值给CMAKE_FIND_ROOT_PATH,比如set(CMAKE_FIND_ROOT_PATH /opt/arm /opt/inst)
CMAKE_FIND_ROOT_PATH_MODE_PROGRAM: 对FIND_PROGRAM()起作用,有三种取值,
NEVER,ONLY,BOTH,第一个表示不在CMAKE_FIND_ROOT_PATH下进行查找,
第二个表示只在这个路径下查找,第三个表示先查找这个路径,再查找全局路径
CMAKE_FIND_ROOT_PATH_MODE_LIBRARY: 对FIND_LIBRARY()起作用,表示在链接的时候的库的相关选项,
因此这里需要设置成ONLY来保证我们的库是在交叉环境中找的.
CMAKE_FIND_ROOT_PATH_MODE_INCLUDE: 对FIND_PATH()和FIND_FILE()起作用,一般来说也是ONLY,
如果想改变,一般也是在相关的FIND命令中增加option来改变局部设置
BOOST_ROOT:
对于需要boost库的用户来说,相关的boost库路径配置也需要设置
QT_QMAKE_EXECUTABLE: 相应的qmake路径(指定到qmake本身)
Modern CMake实践
Android.mk
Android编译系统使用
android的 makefile – Android.mk 分析
Android编译系统剖析
Android编译系统分析
理解 Android Build 系统 mm mmm mma croot
Kconfig
Kconfig的角色
Kconfig 有助于使 Linux 内核高度模块化和可定制。Kconfig 为用户提供了许多配置目标:
menuconfig是这些目标中最受欢迎的。这些目标由不同的主程序处理,这些程序由内核提供并在内核构建期间构建。一些目标有 GUI(如menuconfig),而大多数没有。与 Kconfig 相关的工具和源代码主要位于内核源代码中的 scripts/kconfig/ 下。
------------------------------------分隔符------------------------------------
当在内核源码目录下输入make menuconfig时,在出现的菜单界面中选择一项时,它会自动更新.config相应项的值。
如果没有选择,则会在.config问下插入一行注释。类似于# CONFIG_xxx is not set
当输入make时,根据makefile文件来编译,makefile文件中的变量值则由.config来进行赋值操作。
仅仅只在Kconfig中添加选项,只会在菜单界面中显示,即使此时选择y或m,也不会编译文件。
还需要在makefile文件中按照规定添加相应行才能进行编译:obj-$(CONFIG_xxx) += xxx.o。CONFIG_xxx在.config中被定义
简单关系图解如下: Kconfig------->.config(.conf)---------->makefile
Kconfig:定义了配置项
.config:对配置项进行赋值
makefile:建立配置项的生成法则
-
生成.config
-
解析.config
syncconfig将 .config 作为输入并输出许多其他文件: .conf用于makefile文本处理。makefile中将使用的语句:obj-$(CONFIG_xxx) += xxx.o。 autoconf.h 用于C语言的源文件。
-
kbuild
组件式构建,递归make,是GNU make管理大型项目的常用方法。 通过将源文件划分为不同的模块/组件,每个组件都由其自己的makefile管理。 当开始构建时,顶级makefile以正确的顺序调用每个组件的makefile以构建组件,并将它们收集到最终的执行程序中。 kbuild是递归make的一个很好的例子。 ------------------------------------------------------ Makefile: 位于源代码根目录的顶级 makefile .config: 内核配置文件 arch/$(ARCH)/Makefile: 架构的 makefile,用于补充顶级makefile scripts/Makefile.*: 描述所有的kbuild makefile的通用规则 ------------------------------------------------------ 1)顶级makefile会将架构Makefile包含进去,读取 .config 文件 2)在 scripts/ Makefile.* 中定义的例程的帮助下,在每个组件的makefile上调用make,构建组件 3)将所有的中间对象链接为 vmlinux
Kconfig语法
-
CONFIG宏变量参数
bool: 表示该CONFIG宏只能选择y(编译内核)或者n(不编译),不能选择m(编译为模块) tristate: 表示该CONFIG宏可以设置y/m/n三种模式 string: 表示该CONFIG宏可以设为一串字符,如#define CONFIG_XXX "config test" hex: 表示该CONFIG宏可以设为一个十六进制,如#define CONFIG_XXX 0x1234 int: 表示该CONFIG宏可以设为一个整数,如#define CONFIG_XXX 1234
-
常用参数
default y: 表示默认是勾上的,也可以写为default m或者default n help: 帮助提示信息 depends on: 依赖项,如depends on XXX 表示当前宏需要CONFIG_ XXX宏打开的前提下,才能设置它 select : 反依赖项,如 selecton XXX表示当前宏如果是y或者m则会自动设置XXX=y或者m choice: 会生成一个单选框,里面通过多选一方式选择config prompt: 提示信息,对于choice而言,则会用来当做一个单选框入口点的标签 range : 设置用户输入的数据范围,如range 0 100表示数据只能位于0~100 menuconfig: 和config XXX类似,不同的是该选项除了能设置y/m/n外,还可以实现菜单效果(能回车进入该项内部) menu/endmenu:可以理解成一个目录,menu可以把其中一部分配置项包含到一个menu中,这样有利于配置的分类显示 config: 构成Kconfig的最基本单元,其中定义了配置项的详细信息 source: 将另外一个Kconfig文件直接复制到当前位置,类似include。 comment: 注释
Editor
C/C++:
VSCode / Source Insight / Clion / CodeBlocks
python:
PyCharm / sublime text / jupyter