基于Openwrt系统架构,实现应用与驱动的实例。
一、在openwrt系统架构,编写helloworld的应用程序。
第一步先创建目录,项目代码要放在 openwrt根目下的 package 目录中,这里源码写在了 hellworld 的 src 目录下,因为外层还有需要编写的文件。
mkdir -p ~/openwrt/package/hellworld/src
cd ~/openwrt/package/helloworld/src
然后编写 helloworld.c 和源码下的 Makefile 文件
touch helloworld.c Makefile
nano helloworld.c
nano Makefile
helloworld.c 内容如下
#include <stdio.h> | |
int main() | |
{ | |
printf("hello world!\n"); | |
return 0; | |
} |
Makefile 包含了两个编译过程,一个清除的命令
helloworld : helloworld.o | |
$(CC) $(LDFLAGS) helloworld.o -o helloworld | |
helloworld.o : helloworld.c | |
$(CC) $(CFLAGS) -c helloworld.c | |
clean : | |
rm *.o helloworld |
写完上面的代码后,可以简单测试一下,输入 make 编译,生成可执行文件,用 ./ 运行就可以了,使用 make clean 可以清除生成的可执行文件
make
make clean
编写配置文件
这里先进入上一层目录,即 helloworld 目录,并创建一个新的 Makefile 文件
$cd ~/openwrt/package/helloworld
$touch Makefile
接下来编写这个 Makefile 文件,内容如下
include $(TOPDIR)/rules.mk | |
#定义相关信息 | |
PKG_NAME:=helloworld | |
PKG_RELEASE:=1 | |
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) | |
include $(INCLUDE_DIR)/package.mk | |
define Package/helloworld | |
SECTION:=utils | |
CATEGORY:=Utilities | |
TITLE:=Helloworld -- prints a snarky message | |
endef | |
define Package/helloworld/description | |
It's my first package demo. | |
endef | |
define Build/Prepare | |
echo "Here is Package/Prepare" | |
mkdir -p $(PKG_BUILD_DIR) | |
$(CP) ./src/* $(PKG_BUILD_DIR)/ | |
endef | |
define Package/helloworld/install | |
echo "Here is Package/install" | |
$(INSTALL_DIR) $(1)/bin | |
$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/bin/ | |
endef | |
$(eval $(call BuildPackage,helloworld)) |
这里别人写的很清楚,我就拿过来用了,也可以参考官方文档。
第1行 include $(TOPDIR)/rules.mk
一般在Makefile的开头,包含了包的基本信息,比如Makefile中的 $(BUILD_DIR), $(INCLUDE_DIR), $(CP), $(INSTALL_DIR), $(INSTALL_BIN)都是这里定义的.具体内容可以到源码主目录下,查看 rules.mk文件.
3~5行,软件包的信息均以“PKG_”开头,其意思和作用如下
PKG_NAME:软件包名称,将在menuconfig和ipkg可以看到。
PKG_VERSION:软件版本号。
PKG_RELEASE:Makefile的版本号
PKG_SOURCE:源代码的文件名。
PKG_SOURCE_URL:源代码的下载网站位置。
PKG_MD5SUM:源代码文件的效验码。用于核对软件包是否下载正确。
PKG_CAT:源代码文件的解压方法。包括zcat, bzcat, unzip等。
PKG_BUILD_DIR:软件包编译目录。它的父目录为$(BUILD_DIR)。
第7行 include $(INCLUDE_DIR)/package.mk
一般在软件包的基本信息完成后再引入,他定义了用户态软件包的规则。编译包分为用户态和内核模块,用户态软件包使用Package,内核模块使用KernelPackage. $(INCLUDE_DIR)/Kernel.mk文件对于软件包为内核时不可缺少, $(INCLUDE_DIR)/package.mk应用在用户态。接下来讲述用户态软件包。用户程序的编译包以 Package/开头,然后接着软件名,在Package定义中的软件名可以与软件包名不一样,而且可以多个定义。
9~13行
定义包的名称为 helloworld
SECTION : 包的类型为 utils
CATEGORY : 目录为Utilitis,即文件在 menuconfig中的位置;有时还会有 SUBMENU项,即子目录.
TITLE : 用于软件包的简短描述,将显示在 menuconfig中.
URL : 软件包的下载位置。
MAINTAINER : 维护者选项。
DEPENDS : 与其他软件的依赖。即如编译或安装需要其他软件时需要说明。如果存在多个依赖,则每个依赖需用空格分开。依赖前使用+号表示默认显示,即对象沒有选中时也会显示,使用@则默认为不显示,即当依赖对象选中后才显示。
15~17行
软件包的详细描述,将显示在 make menuconfig中
19~23行
编译准备方法,对于网上下载的软件包不需要再描述。对于非网上下载或自行开发的软件包必须说明编译准备方法。本文所用的准备方法就是首先创建软件包目录,然后将源码拷贝到刚刚创建的目录中。按OpenWrt的习惯,一般把自己设计的程序全部放在src目录下。
25~29行
软件包的安装方法,包括一系列拷贝编译好的文件到指定位置。调用时会带一个参数,就是嵌入系统的镜像文件系统目录,因此$(1)表示嵌入系统的镜像目录。
INSTALL_DIR:=install -d -m0755 : 创建所属用戶可读写、执行,其他用戶可读可执行的目录
INSTALL_BIN:=install -m0755 : 编译好的文件到镜像文件目录
31行 $(eval $(call BuildPackage,helloworld))
完成前面定义后,必须使用eval函数实现各种定义。其格式为:
对于一般软件包: $(eval ( c a l l P a c k a g e , (call Package,(callPackage,(PKG_NAME)))
或对于内核模块: $(eval ( c a l l K e r n e l P a c k a g e , (call KernelPackage,(callKernelPackage,(PKG_NAME)))
如果一个软件包有多个程序,例如:一个应用程序有自己的内核模块,上面使用的 PKG_NAME需要灵活变通。 eval函数可能设计多个。也可以当成多个软件包处理。
编译软件
这里要回到 openwrt 的主目录编译软件
cd ~/openwrt
在 menu 中选中我们添加的软件
make menuconfig
还记得我们写的配置文件吗?我们定义了软件目录。
define Package/helloworld
SECTION:=utils
CATEGORY:=Utilities
TITLE:=Helloworld -- prints a snarky message
endef
在 openwrt 菜单首页的 Utilities中找到 helloworld,使用空格键勾选上,保存退出。
接下来在 openwrt 的根目录下,单独编译我们的软件
make package/helloworld/compile V=s
应该可以在 openwrt\bin\ramips\ 下的某个目录找到,也可以用下面命令
find bin/ -name "helloworld*.ipk"
软件安装
具体如何使用 SFTP 传文件可以看我上一篇博客,下面讲讲安装软件,下面是一些命令
opkg install xxx.ipk
opkg update #更新可以获取的软件包列表
opkg upgrade #对已经安装的软件包升级
opkg list #获取软件列表
opkg install #安装指定的软件包
opkg remove #卸载已经安装的指定的软件包
运行软件
在 openwrt 板子上输入 helloworld并按下回车,应该就会输出我们代码里输出的内容
helloworld
hello world!
二、在openwrt系统架构,编写helloworld驱动程序。
1、OpenWRT中的驱动
Openwrt源码中,所有扩展的软件包都在package目录下,自己添加的应用放在该目录下。
所有扩展的内核驱动都在package/kernel目录下,自己添加的驱动放在该目录下。
2、添加驱动步骤
在package/kernel目录下添加一个helloworld文件夹
在helloworld添加一个Makefile文件。具体Makefile怎么写,我们先看两个kernel中自带的驱动的Makefile文件。
I2C驱动
#
# Copyright (C) 2008 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
# I2C驱动
#包含上两级目录配置
include $(TOPDIR)/rules.mk # TOPDIR : /openwrt
include $(INCLUDE_DIR)/kernel.mk # INCLUDE_DIR: /openwrt/include
PKG_NAME:=i2c-gpio-custom #驱动名字
PKG_RELEASE:=2 #Makefile的版本号
include $(INCLUDE_DIR)/package.mk #包含上一级目录配置
# make menuconfig时在配置界面上显示的方式
define KernelPackage/i2c-gpio-custom
SUBMENU:=I2C support #显示的子选项
TITLE:=Custom GPIO-based I2C device #显示的内容
DEPENDS:=@GPIO_SUPPORT +kmod-i2c-core +kmod-i2c-gpio #依赖于其他模块
FILES:=$(PKG_BUILD_DIR)/i2c-gpio-custom.ko #生成的目标文件
KCONFIG:=
endef
define KernelPackage/i2c-gpio-custom/description
Kernel module for register a custom i2c-gpio platform device. #帮助时显示的内容
endef
EXTRA_KCONFIG:= \
CONFIG_I2C_GPIO_CUSTOM=m #编译成模块
# 无需更改
EXTRA_CFLAGS:= \
$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \
$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG)))) \
# 无需更改
MAKE_OPTS:= \
ARCH="$(LINUX_KARCH)" \ #CPU架构
CROSS_COMPILE="$(TARGET_CROSS)" \ #交叉编译工具
SUBDIRS="$(PKG_BUILD_DIR)" \
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
$(EXTRA_KCONFIG)
#编译前的准备
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/ #PKG_BUILD_DIR:编译时的目录,对应于驱动就是 build_dir/target-**/linux-**/
endef
#编译
define Build/Compile
$(MAKE) -C "$(LINUX_DIR)" \
$(MAKE_OPTS) \
modules
endef
#完成前面定义后,必须使用 eval 函数实现各种定义, KernelPackage代表是内核驱动模块,Package表示应用程序
$(eval $(call KernelPackage,i2c-gpio-custom))
RTC驱动
#
# Copyright (C) 2006-2009 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
# RTC驱动
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=rtc-rv5c386a
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define KernelPackage/rtc-rv5c386a
SUBMENU:=Other modules
DEPENDS:=@TARGET_brcm47xx
TITLE:=Driver for RTC RV5C386A (used in WL-700gE and WL-HDD)
AUTOLOAD:=$(call AutoLoad,70,rtc)
FILES:=$(PKG_BUILD_DIR)/rtc.ko
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
#有时候CROSS_COMPILE、ARCH、SUBDIRS、EXTRA_CFLAGS会被独立成一个变量,然后再去引用
define Build/Compile
$(MAKE) -C "$(LINUX_DIR)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
ARCH="$(LINUX_KARCH)" \
SUBDIRS="$(PKG_BUILD_DIR)" \
EXTRA_CFLAGS="$(BUILDFLAGS)" \
modules
endef
$(eval $(call KernelPackage,rtc-rv5c386a))
根据上面的注释和解释,并对比两份Makefile,我们发现写的基本结构都是相似的,所以我们可以根据上面的模板来自行写一份。
以I2C为模板:
#
# Copyright (C) 2008 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=helloworld
PKG_RELEASE:=2
include $(INCLUDE_DIR)/package.mk
define KernelPackage/helloworld
SUBMENU:=Other modules
TITLE:=HelloWorld
FILES:=$(PKG_BUILD_DIR)/helloworld.ko
KCONFIG:=
endef
define KernelPackage/helloworld/description
Kernel module for register helloworld.
endef
EXTRA_KCONFIG:= \
CONFIG_HELLOWORLD=m
EXTRA_CFLAGS:= \
$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter %=m,$(EXTRA_KCONFIG)))) \
$(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter %=y,$(EXTRA_KCONFIG)))) \
MAKE_OPTS:= \
ARCH="$(LINUX_KARCH)" \
CROSS_COMPILE="$(TARGET_CROSS)" \
SUBDIRS="$(PKG_BUILD_DIR)" \
EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
$(EXTRA_KCONFIG)
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
define Build/Compile
$(MAKE) -C "$(LINUX_DIR)" \
$(MAKE_OPTS) \
modules
endef
$(eval $(call KernelPackage,helloworld))
基本上就是I2C改成helloworld就OK了!
3、在helloworld文件夹下再新建一个src文件夹,在src下新建一个Kconfig文件。文件内容:
# 该文件是make menuconfig显示界面会读取的文件
config HELLOWORLD
tristate "HelloWorld driver"
default n
help
This is an HelloWorld Driver!
再新建一个Makefile文件,内容为:
obj-${CONFIG_HELLOWORLD} += helloworld.o
最后新建一个helloworld.c的驱动文件,内容为:
#include <linux/module.h>
#include <linux/kernel.h>
//insmod会执行该函数
static int __init helloworld_init(void)
{
printk("helloworld driver init !\n");
return 0;
}
//rmmod会执行该函数
static int __exit helloworld_exit(void)
{
printk("helloworld driver exit !\n");
return 0;
}
//声明出入口函数
module_init(helloworld_init);
module_exit(helloworld_exit);
MODULE_AUTHOR("YANG");
MODULE_LICENSE("GPL");
4、接下来就是编译了
先make menuconfig将驱动配置一下。
保存后执行
make package/kernel/helloworld/compile V=99
编译出来的驱动模块在openwrt/bin/ramips/packages/kernel/kmod-helloworld_4.4.7-2_ramips_24kec.ipk
5、拷贝ipk安装包并运行
运行lsmod命令可以查看当前模块:
lsmod
运行后重启板子或者vsftpd服务即可传输文件(其实直接用也行,要是不行就做这一步),传输完ipk安装包后进入到ipk安装包所在目录,使用opkg安装:
./bin/ar71xx/packages/base/kmod-helloworld_4.4.60-2_ar71xx.ipk
opkg install kmod-helloworld_4.4.60-2_ar71xx.ipk
然后分别运行以下两条命令安装和:
insmod helloworld.ko
lsmod
运行dmesg命令查看内核缓冲区即可看到打印内容
dmesg
卸载模块:
rmmod helloworld.ko
顺便提一下如果想要卸载刚才装的ipk安装包的软件,运行以下命令
opkg list_installed
查看安装软件的列表,然后运行opkg remove xxxx(xxxx为列表里的名字),原来ipk安装包的名字是无效的噢。
相关文章:
基于Openwrt系统架构,实现应用与驱动的实例。
一、在openwrt系统架构,编写helloworld的应用程序。 第一步先创建目录,项目代码要放在 openwrt根目下的 package 目录中,这里源码写在了 hellworld 的 src 目录下,因为外层还有需要编写的文件。 mkdir -p ~/openwrt/package/hel…...
SQL进阶技巧:如何利用三次指数平滑模型预测商品零售额?
目录 0 问题背景 1 数据准备 2 问题解决 2.1 模型构建 (1)符号规定 (2)基本假设...

HTB:Cicada[WriteUP]
目录 连接至HTB服务器并启动靶机 使用nmap对靶机进行开放端口扫描 使用nmap对靶机开放端口进行脚本、服务信息扫描 首先尝试空密码连接靶机SMB服务 由于不知道账户名,这里我们使用crackmapexec对smb服务进行用户爆破 通过该账户连接至靶机SMB服务器提取敏感信…...
小张求职记四
学校食堂的装修富丽堂皇,像个金碧辉煌的宫殿,可实际上却充斥着廉价的塑料制品和刺鼻的消毒水味。这金玉其外败絮其中的景象,与食堂承包商的“精明算计”如出一辙。 小张和小丽应约来到了一个档口下,“红烧肉”,之前就是…...

适用于 c++ 的 wxWidgets框架源码编译SDK-windows篇
本文章记录了下载wxWidgets源码在windows 11上使用visual Studio 2022编译的全过程,讲的不详细请给我留言,让我知道错误并改进。 本教程是入门级。有更深入的交流可以留言给我。 如今互联网流行现在大家都忘记了这块桌面的开发,我认为桌面应用还是有用武之地,是WEB无法替代…...

flink 内存配置(二):设置TaskManager内存
TaskManager在Flink中运行用户代码。根据需要配置内存使用,可以极大地减少Flink的资源占用,提高作业的稳定性。 注意下面的讲解适用于TaskManager 1.10之后的版本。与JobManager进程的内存模型相比,TaskManager内存组件具有类似但更复杂的结构…...

【C++ 算法进阶】算法提升八
复杂计算 (括号问题相关递归套路 重要) 题目 给定一个字符串str str表示一个公式 公式里面可能有整数 - * / 符号以及左右括号 返回最终计算的结果 题目分析 本题的难点主要在于可能会有很多的括号 而我们直接模拟现实中的算法的话code会难写 要考虑…...
阿里云实时数据仓库HologresFlink
1. 实时数仓Hologres特点 专注实时场景:数据实时写入、实时更新,写入即可见,与Flink原生集成,支持高吞吐、低延时、有模型的实时数仓开发,满足业务洞察实时性需求。 亚秒级交互式分析:支持海量数据亚秒级交…...
生成式语言模型的文本生成评价指标(从传统的基于统计到现在的基于语义)
文本生成评价指标 以 BLEU 为代表的基于统计的文本评价指标基于 BERT 等预训练模型的文本评价指标 1.以 BLEU 为代表的基于统计的文本评价指标 1.BLEU(Bilingual Evaluation Understudy, 双语评估辅助工具) 所有评价指标的鼻祖,核心思想是比较 候选译文 和 参考…...
【网安案例学习】暴力破解攻击(Brute Force Attack)
### 案例与影响 暴力破解攻击在历史上曾导致多次重大安全事件,特别是在用户数据泄露和账户被盗的案例中。随着计算能力的提升和密码管理技术的进步,暴力破解的威胁虽然有所减弱,但仍需警惕,特别是在面对高价值目标时。 【故事一…...

时间序列预测(十八)——实现配置管理和扩展命令行参数解析器
如图,这是一个main,py文件,在此代码中,最开始定义了许多模型参数,为了使项目更加灵活和可扩展,便于根据不同的需求调整参数和配置,可以根据实际需要扩展参数和配置项。 下面是如何实现配置管理和扩展命令行…...
Vue问题汇总解决
作者:fyupeng 技术专栏:☞ https://github.com/fyupeng 项目地址:☞ https://github.com/fyupeng/distributed-blog-system-api 留给读者 我们经常在使用Vue开发遇到一些棘手的问题,解决后通常要进行总结,避免下次重复…...

Spark学习
Spark简介 1.Spark是什么 首先spark是一个计算引擎,而不是存储工具,计算引擎有很多: 第一代:MapReduce廉价机器实现分布式大数据处理 第二代:Tez基于MR优化了DAG,性能比MR快一些 第三代:Spark…...
一些小细节代码笔记汇总
Python cv2抓取摄像头图片保存到本地 import cv2 import datetime, ossavePath "E:/Image/"if not os.path.exists(savePath):os.makedirs(savePath)cap cv2.VideoCapture(0) capture Falseif not cap.isOpened():print("无法打开摄像头")exit()while…...
L4.【LeetCode笔记】链表题的VS平台调试代码
不用调用87.【C语言】数据结构之链表的头插和尾插文章提到的头插函数 记下这个模板代码,可用于在Visual Studio上调试出问题的测试用例 如创建链表[1,2,3,4,5] #include <stdilb.h> // Definition for singly-linked list.struct ListNode {int val;struct ListNode *…...
JavaCV 之高斯滤波:图像降噪与细节保留的魔法
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程,高并发设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s…...

VsCode显示空格
ctrl shift p选择Preferences: Open User Settings (JSON) 加上"editor.renderWhitespace": "all" {"cmake.configureOnOpen": true,"files.encoding": "gb2312","editor.fontVariations": false,"edito…...
.Net C# 基于EFCore的DBFirst和CodeFirst
DBFirst和CodeFirst 1 概念介绍 1.1 DBFirst(数据库优先) 含义:这种模式是先创建数据库架构,包括表、视图、存储过程等数据库对象。然后通过实体框架(Entity Framework)等工具,根据已有的数据…...

w012基于springboot的社区团购系统设计
🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板ÿ…...
笔记本降频超鬼锁屏0.39电脑卡到不行解决办法实操记录
1、最开始没发现cpu问题,我发现我电脑突然异常的卡顿,最开始我怀疑是不是微软win用久了或者自动更新导致的问题,于是自己重装了操作系统 发现问题依然存在 2、我怀疑难道我的 cpu 内存 固态硬盘 其中一个有点问题?心想要是硬盘的…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
Oracle查询表空间大小
1 查询数据库中所有的表空间以及表空间所占空间的大小 SELECTtablespace_name,sum( bytes ) / 1024 / 1024 FROMdba_data_files GROUP BYtablespace_name; 2 Oracle查询表空间大小及每个表所占空间的大小 SELECTtablespace_name,file_id,file_name,round( bytes / ( 1024 …...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...

苍穹外卖--缓存菜品
1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据,减少数据库查询操作。 缓存逻辑分析: ①每个分类下的菜品保持一份缓存数据…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...