@我真的很想重视能力提升,但是总能眼里略过问题。
基于软路由openwrt,进行自己代码的模块编译,实现第一个样例代码helloworld,这里遇到过很多的问题。
1. 问题
1: 源码包和SDK包的区别?
ImageBuilder:是编译完整固件用的,我们只编译ipk软件包所以用不到,
SDK包 : SDK将与该平台无关的程序都取消掉,只留下了编译需要用的工具和平台相关的代码,也就是说SDK是基础的编译环境,我们在上面选择对应的模块进行编译就好!!! ===》含有交叉编译环境用到的toolchain
用du -sh查看下大小,只占了几百M,源工程可是有好几G呢
源码包: 可以通过make menuconfig 选择对应的目标文件进行生成,可以选择生成SDK等
2:正确编写一个样例代码的流程?
1:安装基础的依赖组件包
2:单纯依赖SDK包中的编译环境,直接配置我们的模块代码(在package目录中),单独编译我们的模块就ok ===》SDK是基础的编译环境,编译哪个由我们自己选择。
3:单独编译我们的模块 make -j1 V=cs package/模块名称/compile
3: Makefile报错问题的排查!
特别注意:遇到报错,要去分析报错!!!
问题:关注了行号看不出问题,请一定要多理解后面报错的涵义去分析问题
4: make menuconfig中对应的选项,有什么关系?
以及默认的选项,单独执行make进行全编译的时候为什么有很多的不通过?
2. 基于ubuntu20.4的纯净环境,使用我们的sdk(openwrt-sdk-ramips-mt7621_gcc-7.4.0_musl.Linux-x86_64.tar)进行样例代码的编译:
1:安装相关的基础包
sudo apt update
sudo apt upgrade
sudo apt install make
sudo apt-get install build-essential
2:参考官网https://openwrt.org/docs/guide-developer/build-system/install-buildsystem,安装对应的需要依赖。
hlp@ubuntu:~/openwrt/openwrt-sdk-ramips-mt7621_gcc-7.4.0_musl.Linux-x86_64/package$ sudo apt install build-essential ccache ecj fastjar file g++ gawk gettext git java-propose-classpath libelf-dev libncurses5-dev libncursesw5-dev libssl-dev python python2.7-dev python3 unzip wget python3-distutils python3-setuptools rsync subversion swig time xsltproc zlib1g-dev
3:配置样例代码,并进行编译。
hlp@ubuntu:~/openwrt/openwrt-sdk-ramips-mt7621_gcc-7.4.0_musl.Linux-x86_64/package$ tree helloworld/
helloworld/
├── helloworld.c
└── Makefile
0 directories, 2 files
hlp@ubuntu:~/openwrt/openwrt-sdk-ramips-mt7621_gcc-7.4.0_musl.Linux-x86_64/package$ cd ../
hlp@ubuntu:~/openwrt/openwrt-sdk-ramips-mt7621_gcc-7.4.0_musl.Linux-x86_64$ make -j V=s package/helloworld/compile
... #这里注意会不会有错误
hlp@ubuntu:~/openwrt/openwrt-sdk-ramips-mt7621_gcc-7.4.0_musl.Linux-x86_64$ find -name *.ipk |grep hello
./bin/packages/mipsel_24kc/base/helloworld_1.0-1_mipsel_24kc.ipk
hlp@ubuntu:~/openwrt/openwrt-sdk-ramips-mt7621_gcc-7.4.0_musl.Linux-x86_64$
可以看到,在SDK包目录下package目录中写自己的样例代码,只要实现样例代码以及对应的Makefile,特别注意Makefile中tab键不能是空格。
helloworld.c
#include <stdio.h>
int main()
{
printf("\n hello world!\n");
return 0;
}
Makefile ===>这里的不规范导致我持续处理了好久,不能用八个空格代表tab
注意:这里的makefile中有个源码路径,需要修改
include $(TOPDIR)/rules.mk
# Name, version and release number
# The name and version of your package are used to define the variable to point to the build directory of your package: $(PKG_BUILD_DIR)
PKG_NAME:=helloworld
PKG_VERSION:=1.0
PKG_RELEASE:=1
# Source settings (i.e. where to find the source codes)
# This is a custom variable, used below
SOURCE_DIR:=/home/hlp/openwrt/openwrt-sdk-ramips-mt7621_gcc-7.4.0_musl.Linux-x86_64/package/helloworld
include $(INCLUDE_DIR)/package.mk
# Package definition; instructs on how and where our package will appear in the overall configuration menu ('make menuconfig')
define Package/helloworld
SECTION:=examples
CATEGORY:=Examples
TITLE:=Hello, World!
endef
# Package description; a more verbose description on what our package does
define Package/helloworld/description
A simple "Hello, world!" -application.
endef
# Package preparation instructions; create the build directory and copy the source code.
# The last command is necessary to ensure our preparation instructions remain compatible with the patching system.
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
cp $(SOURCE_DIR)/* $(PKG_BUILD_DIR)
$(Build/Patch)
endef
# Package build instructions; invoke the target-specific compiler to first compile the source file, and then to link the file into the final executable
define Build/Compile
$(TARGET_CC) $(TARGET_CFLAGS) -o $(PKG_BUILD_DIR)/helloworld.o -c $(PKG_BUILD_DIR)/helloworld.c
$(TARGET_CC) $(TARGET_LDFLAGS) -o $(PKG_BUILD_DIR)/$1 $(PKG_BUILD_DIR)/helloworld.o
endef
# Package install instructions; create a directory inside the package to hold our executable, and then copy the executable we built previously into the folder
define Package/helloworld/install
$(INSTALL_DIR) $(1)/usr/bin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/usr/bin
endef
# This command is always the last, it uses the definitions and variables we give above in order to get the job done
$(eval $(call BuildPackage,helloworld))
我么可以参考模板进行我们项目配置,注意 CATEGORY:=Examples 这行命令把我们的模块配置在了menuconfig中,$(INSTALL_DIR) $(1)/usr/bin 是我们目标文件的生成位置。
4: 上传ipk到对应的固件环境,安装并执行:
opkg install /tmp/helloworld_1.0-1_mipsel_24kc.ipk
安装包安装完成后,直接在串口终端输入:hello_world
root@transCOMM:/tmp# opkg install helloworld_1.0-1_mipsel_24kc.ipk
Installing helloworld (1.0-1) to root...
Configuring helloworld.
Collected errors:
* opkg_conf_parse_file: Duplicate src declaration (openwrt_base http://downloads.openwrt.org/snapshots/packages/mipsel_24kc/base). Skipping.
* opkg_conf_parse_file: Duplicate src declaration (openwrt_luci http://downloads.openwrt.org/snapshots/packages/mipsel_24kc/luci). Skipping.
* opkg_conf_parse_file: Duplicate src declaration (openwrt_packages http://downloads.openwrt.org/snapshots/packages/mipsel_24kc/packages). Skipping.
root@transCOMM:/tmp# helloworld
hello world!
root@transCOMM:/tmp#
3. 遗留一些疑问:
1: 单独的SDK包,是基础的编译环境,用make package/XXX/compile 进行编译单独的模块,如果有默认的选项,用make直接编译,不通过?
2:Makefile的使用技巧及问题排查。
3:其他可以试试在别的模块写代码,配置 feeds.conf进行连接自己的模块编译,或者分层级的makefile编译。
4:openwrt虚拟机,openwrt整体编译, 刷固件等可以待研究。
5:openwrt安装第三方模块(openwrt官方源中下载,可以使用svn或者git方式下载包)? make package/XXX/download make package/XXX/prepare make package/XXX/compile ==>https://dev.openwrt.org/browser/packages/utils/nano (如namo的包)
6:openwrt自动编译固件升级?GitHub Actions云编译OpenWrt?参考: https://gitee.com/coray/openwrt#https://pan.baidu.com/s/1RVi4nN8Y1ak9LTWzhV5bSQ
openwrt官网文档可以查看:https://openwrt.org/docs/start
openwrt相关包下载:https://downloads.openwrt.org/
4. 其他源码目录了解等:
交叉编译环境运行生成的文件是不可以在我们的环境直接运行的,需要拷贝到对应的环境上去运行。
1:构建交叉编译环境:(可以解压到opt目录下,也可以source /etc/bash.bashrc中修改环境变量)
1:通过源码包staging_dir目录下直接有toolchain,设置环境变量,使用mipsel-openwrt-linux-gcc -v进行验证
export PATH=$PATH:"/home/ubuntu/0407_AT/openwrt-sdk-ramips-mt7621_gcc-7.4.0_musl.Linux-x86_64/staging_dir/toolchain-mipsel_24kc_gcc-7.4.0_musl/bin"
export STAGING_DIR='/home/ubuntu/0407_AT/openwrt-sdk-ramips-mt7621_gcc-7.4.0_musl.Linux-x86_64/staging_dir'
2:可以使用make menuconfig 选上toolchain,会在bin/ramips/目录生成toolchain包,解压后设置环境变量即可
Target System:你的路由器的Soc架构
Subtarget:你的路由器Soc的型号
Target Profile:你的路由器的型号
Build the OpenWrt SDK:是否选择编译SDK,按需选择
SDK可用于交叉编译
Libraries:Linux的库
LuCI:路由器的网页界面
Utilities:Linux下的工具
2:openwrt代码库目录层级的含义?
build_dir:用来解压所有的源代码和编译它们的位置
staging_dir:用来安装所有已编译软件的位置,或者用来存放用来打包、组装固件的文件。
build_dir文件夹中有三个区域:
build_dir/host:用来编译所有跑在主机上的程序(OpenWRT从源中编译他自己版本的sed和其它许多工具)。
这个区域将用来编译仅跑在你主机上的程序。
build_dir/toolchain:用来编译打包中使用到的C交叉编译器和C标准库组件。
这个区域将用来编译仅跑在你住几上的程序(例如:C交叉编译器)以及设计的跑在目标机器上的链接库,例如uClibc, libm, pthreads等等。
build_dir/target:用于编译目标系统的实际的包,和Linux内核。
staging_dir下也有三个区域:
staging_dir/host:该文件夹是一个微型的Linux 根目录,有自己的目录bin/, lib/等等。
这是主机工具安装的位置,构建系统的其余部分会将该区域的目录前缀到环境变量PATH中。
staging_dir/toolchain:该文件夹是一个微型的Linux 根目录,有自己的目录bin/, lib/等等。
它包含用来构建固件的C交叉编译器。
你可以用该编译器在OpenWRT之外编译一个可以加载到固件中的简单的C程序。
这个C编译器一般是这样:staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-uclibc-gcc。
你可以看到CPU、C库和编码到其中的gcc的版本号;
并且允许多目标同时在一起构建。
staging_dir/target:包含每个目标包已安装的版本;
根目录形式,包含bin/, lib/等等,并且将会变成实际的根目录,仅作出一些调整就会打包进固件镜像中,像root-ar71xx之类的。这里也有一些其它的文件在其中,主要生成软件包和开发软件包。
3:不同命名的安装包的含义? 以及如何使用这些安装包。
相关的bin文件就是生成的固件,刷进自己的固件中就可以了。
4:如何选择系统对应的openwrt版本?
5:交叉编译环境编译出来的可执行文件是无法运行的,需要拷贝到开发板上? 那么,如何安装openwrt虚拟机
使用交叉编译环境如何生成ipk文件
make的时候 选用参数 host指定交叉编译环境的gcc
查看固件对应的openwrt版本:https://openwrt.org/toh/views/toh_fwdownload
6:源码实现: bin文件是最终的刷入固件中的样式
我们可以实现正确的二进制文件,直接进行运行?
我们可以实现openwrt的模块(ipk),使用opkg进行安装
7:定制自己的固件:
有三种方法编译openwrt定制固件。 https://blog.csdn.net/wsclinux/article/details/46311893
1. 用ImageBuilder编译,用于灵活选择package。毕竟压缩的只读文件系统squashfs比可写的JFFS能省不少地方,可以用来把玩更多的package。 https://www.right.com.cn/forum/thread-4087041-1-1.html
tar xvJf openwrt-imagebuilder-19.07.7-ramips-mt7621.Linux-x86_64.tar.xz
cd openwrt-imagebuilder-19.07.7-ramips-mt7621.Linux-x86_64/
make info
make image PROFILE=youhua_wr1200js PACKAGES="luci luci-i18n-base-zh-cn luci-i18n-firewall-zh-cn luci-i18n-opkg-zh-cn luci-lib-ipkg ddns-scripts luci-app-ddns luci-i18n-ddns-zh-cn"
最后在bin目录下生成对应的固件
2. 用SDK编译,用于编译package仓库中没有的软件包,另外其中有配套的内核源码及头文件,编译缺失的内核模块也很方便。
3. 从源码编译,因为要重新编译cross-compile toolchians,下载最内核和软件包的源码编译,导致这个过程比较耗时,用于上述两种情况搞不定的情况。
https://qiedd.com/344.html