@我真的很想重视能力提升,但是总能眼里略过问题。
基于软路由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