一些问题
编译 openwrt 时部分工具报错 No such file or directory
64 位系统运行 32 位程序,需要 32 位库支持;
1
sudo apt-get install lib32z1 lib32stdc++6
如何编译 openwrt 程序包
编译步骤
-
先在 openwrt 根目录加载环境变量和 shell 函数;
1
source build/envsetup.sh
-
选择平台(配置)
1
lunch <你的平台号>
-
在 openwrt 包目录(如
package/xxx/your_app
目录)下使用:该命令可以重新编译当前目录的 openwrt 包;
1
mm -B
mm 命令来自哪里?
mm 命令是一个 shell 函数(在 build/envsetup.sh
中有定义,实际指向了 scripts/mm.sh
);
在 script/mm.sh
中可以看到 mm 函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
function mm() {
local T=$1/
local orgin=`pwd`
local path=`pwd`
#find target makefile
#trap 'echo $orgin >> ~/mm; trap - SIGINT; ' SIGINT
while [ x`pwd` != x$T ] && [ x`pwd` != x"/" ]
do
find -maxdepth 1 -name Makefile | xargs cat | grep "define Package" > /dev/null
is_package=$?
find -maxdepth 1 -name Makefile | xargs cat | grep "define KernelPackage" > /dev/null
is_kernel_package=$?
if [ $is_package -eq 1 ] && [ $is_kernel_package -eq 1 ]; then
cd ../
else
path=`pwd`
target=${path#*$T}
cd $T
cmd="install V=s"
for i in $*; do
[ x$i = x"-B" ] && {
# -B clean the package
print_red "make $target/clean V=s"
make $target/clean V=s
}
[ x${i:0:2} = x"-j" ] && cmd=$cmd" "$i
[ x${i:0:2} = x"-z" ] && export COMPILE_QUICK=1
done
print_red "compile option: ${COMPILE_QUICK}"
print_red "make $target/$cmd"
make $target/$cmd
cd $orgin
#trap - SIGINT
return
fi
done
cd $orgin
#trap - SIGINT
print_red "Can't not find Tina Package Makefile!"
}
在 package/test/myapp
目录中执行 mm -B
,其作用和在 sdk 根目录执行如下命令效果相同:
make package/test/myapp/clean V=s
make package/test/myapp/install
那么像 package/test/myapp/your_cmd
这么长的 target 是怎么匹配的呢?
- sdk 根目录 makefile:
include build/toplevel.mk
; - build/toplevel.mk:有一个万能匹配符号
%::
,这里调用了子目录 makefile;
查看下 package/test/myapp/Makefile
:
1
2
3
4
5
6
7
8
9
10
11
12
13
include $(TOPDIR)/rules.mk
PKG_NAME:=myapp
PKG_RELEASE:=1
PKG_BUILD_DIR := $(COMPILE_DIR)/$(PKG_NAME)
include $(BUILD_DIR)/package.mk
Package/myapp=XXXXXX
Build/Prepare=YYYYYY
Package/myapp/install=ZZZZZZ
$(eval $(call BuildPackage,$(PKG_NAME)))
目标 makefile 中的靶还应该加上 include 文件中的 target:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
.PHONY: prepare-package-install
prepare-package-install:
@mkdir -p $(PKG_INFO_DIR)
@touch $(PKG_INSTALL_STAMP).clean
@echo "$(filter-out essential,$(PKG_FLAGS))" > $(PKG_INSTALL_STAMP).flags
$(PACKAGE_DIR):
mkdir -p $@
dumpinfo:
download:
prepare:
configure:
compile: prepare-package-install
install: compile
clean: FORCE
$(CleanStaging)
$(call Build/UninstallDev,$(STAGING_DIR),$(STAGING_DIR_HOST))
$(Build/Clean)
rm -f $(STAGING_DIR)/packages/$(STAGING_FILES_LIST) $(STAGING_DIR_HOST)/packages/$(STAGING_FILES_LIST)
rm -rf $(PKG_BUILD_DIR)
dist:
$(Build/Dist)
distcheck:
$(Build/DistCheck)
也就是,默认执行 prepare-package-install 操作,可选择执行的操作有:clean、install 等;
接着查看 build/package.mk
中 BuildPackage:
- inlcude $(TOPDIR)/overlay/*/$(PKG_NAME).mk 文件;
- 如果没有定义 TITLE 就使用一个默认值;
- 将包添加到 BUILD_PACKAGES 变量中;
-
找出包的依赖库;
- 判断目标是否定义了 FIELD, TITLE CATEGORY SECTION VERSION 变量,没定义就报错;
$(call Build/DefaultTargets,$(1))
进行默认目标构建流程;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
define BuildPackage
$(Build/IncludeOverlay)
$(eval $(Package/Default))
$(eval $(Package/$(1)))
ifdef DESCRIPTION
$$(error DESCRIPTION:= is obsolete, use Package/PKG_NAME/description)
endif
ifndef Package/$(1)/description
define Package/$(1)/description
$(TITLE)
endef
endif
BUILD_PACKAGES += $(1)
$(STAMP_PREPARED): $$(if $(QUILT)$(DUMP),,$(call find_library_dependencies,$(DEPENDS)))
$(foreach FIELD, TITLE CATEGORY SECTION VERSION,
ifeq ($($(FIELD)),)
$$(error Package/$(1) is missing the $(FIELD) field)
endif
)
$(if $(DUMP), \
$(Dumpinfo/Package), \
$(foreach target, \
$(if $(Package/$(1)/targets),$(Package/$(1)/targets), \
$(if $(PKG_TARGETS),$(PKG_TARGETS), ipkg) \
), $(BuildTarget/$(target)) \
) \
)
$(if $(PKG_HOST_ONLY)$(DUMP),,$(call Build/DefaultTargets,$(1)))
endef
如何添加自己的软件包
无需编译的纯脚本
在 sdk 根目录新建目录 package/tina_demo/demo_sh
;
文件如下:
1
2
3
.
|--demo_echo.sh
|--Makefile
其中 Makefile 如下:
-
Package/$(PKG_NAME) 描述包的基础信息;
make menuconfig
时首先会扫描所有的包信息存放到tmp/.config-package.in
中,然后通过字符界面进行显示; -
Package/$(PKG_NAME)/description 描述包;
进入
make menuconfig
模式后,在 demo_sh 选项上按下 “?” 后会显示; -
Build/Prepare 是编译准备流程,一般需要建立编译目录,然后将需要的资源拷贝进去;
如果不设置,默认会执行 Build/Prepare/Default 流程;
-
Build/Compile 是编译流程,不需要编译就将该项覆盖为空;
如果不设置,默认会执行 Build/Compile/Default 流程;
-
Package/$(PKG_NAME)/install 是包的安装流程;
需要
make menuconfig
选中 demo_sh 项后,mm -B
的 install 步骤才能生效;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
include $(TOPDIR)/rules.mk
PKG_NAME:=demo_sh
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(COMPILE_DIR)/$(PKG_NAME)_$(PKG_VERSION)
include $(BUILD_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=exe
CATEGORY:=tina demo
TITLE:=echo shell
endef
define Package/$(PKG_NAME)/description
demo_sh
a echo shell script
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./* $(PKG_BUILD_DIR)/
endef
define Build/Compile
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/robot/bin
$(INSTALL_BIN) ./demo_echo.sh $(1)/usr/robot/bin/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))
验证步骤:
-
新建包目录和其中的文件;
- Makefile 内容参考上面;
- demo_echo.sh 测试脚本,内容任意,不需要执行权限,$(INSTALL_BIN) 操作会赋予该文件权限;
-
进入 sdk 根目录,输入
make menuconfig
选中新增的项,然后保存退出; -
回到第一步建立的包目录中,输入
mm -B
进行编译;如果你使用的 vscode,发现左侧列表中没有生成文件夹或文件,刷新下文件列表;
-
out/my_platform/compile_dir/target 中会创建 demo_sh_1.0.0 目录(Prepare 产生);
-
out/my_platform/staging_dir/target/rootfs 中会存在 usr/robot/bin/demo_echo.sh 文件(install 产生);
值得注意的是,上述目录的 rootfs 是一个样板目录,很多文件的权限和所有者并不正确,仅供参考,不要把它和小机运行的根文件系统画等号;
-
-
再次进入 sdk 根目录,进行打包操作:
1 2 3 4 5 6 7 8 9 10
# [可选] 编译(不要用 root 账户) # 字符选择模式去掉一个软件包后应该重新 make 一次,可以有效去除 rootfs 中多余的文件 # 应该是把 rootfs 全部清理,然后将目前勾选的软件包添加到 rootfs make -j6 # 打包镜像,路径 out/my_platform/(vscode 需要刷新下文件列表) pack # 生成 ota 包,路径 out/my_platform/ota(vscode 需要刷新下文件列表) make_ota_image
Makefile 编译形式
在 sdk 根目录新建目录 package/tina_demo/demo_makefile
;
文件如下:
1
2
3
4
5
6
.
|--src
| |--demo_print.c
| |--Makefile
|
|--Makefile
src/demo_print.c 如下:
1
2
3
4
5
6
7
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("hello world!\r\n");
return 0;
}
src/Makefile 如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
target = demo_print
INCLUDES += -I.
SRCS = demo_print.c
OBJS = $(SRCS:.c=.o)
install:$(target)
@mkdir -p $(CONFIG_PREFIX)/usr/bin
@cp $(target) $(CONFIG_PREFIX)/usr/bin
%.o:%.c
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
$(target): $(OBJS)
$(CC) $(INCLUDES) $(LDFLAGS) $^ -o $@
all: install
clean:
rm -rf $(target) $(OBJS)
顶层 Makefile 如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
include $(TOPDIR)/rules.mk
PKG_NAME:=demo_makefile
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(COMPILE_DIR)/$(PKG_NAME)_$(PKG_VERSION)
include $(BUILD_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=exe
CATEGORY:=tina demo
TITLE:=print c(makefile)
endef
define Package/$(PKG_NAME)/description
demo_makefile
a print c program
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) -r ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C $(PKG_BUILD_DIR)/ \
ARCH="$(TARGET_ARCH)" \
AR="$(TARGET_AR)" \
CC="$(TARGET_CC)" \
CXX="$(TARGET_CXX)" \
CFLAGS="$(TARGET_CFLAGS)" \
LDFLAGS="$(TARGET_LDFLAGS)" \
CONFIG_PREFIX="$(PKG_INSTALL_DIR)" \
all
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/robot/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/* $(1)/usr/robot/bin/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))
cmake 编译形式
在 sdk 根目录新建目录 package/tina_demo/demo_cmake
;
文件如下:
1
2
3
4
5
6
.
|--src
| |--demo_print.c
| |--CMakeLists.txt
|
|--Makefile
src/demo_print.c 如下:
1
2
3
4
5
6
7
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("hello world!\r\n");
return 0;
}
src/CMakeLists.txt 如下:
1
2
3
4
5
6
cmake_minimum_required(VERSION 3.4)
project(demo_cmake)
add_executable(demo_cmake demo_print.c)
install(TARGETS demo_cmake RUNTIME DESTINATION bin)
顶层 Makefile 如下:
使用默认 cmake 方法进行编译;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
include $(TOPDIR)/rules.mk
PKG_NAME:=demo_cmake
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_BUILD_DIR:=$(COMPILE_DIR)/$(PKG_NAME)_$(PKG_VERSION)
include $(BUILD_DIR)/package.mk
include $(BUILD_DIR)/cmake.mk
define Package/$(PKG_NAME)
SECTION:=exe
CATEGORY:=tina demo
TITLE:=print c(cmake)
endef
define Package/$(PKG_NAME)/description
demo_cmake
a print c program
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) -r ./src/* $(PKG_BUILD_DIR)/
endef
define Package/$(PKG_NAME)/install
$(INSTALL_DIR) $(1)/usr/robot/bin
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/* $(1)/usr/robot/bin/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))