操作系统学习之:ucor_os实验报告(lab1)

ucor_os实验报告(lab1)_makefile文件详解!


练习一 理解通过make生成执行文件的过程

为完成这个练习,需要准备的知识比较多:

  • linux常用命令
    特别是要理解grep、awk、sed这三个命令,以及linux万物兼文件的思想
>文件含义
&0stdin,标准输入文件
&1stdout,标准输出文件
&2stderr,标准错误文件
/dev/null空设备,是一个特殊的设备文件,它丢弃一切写入其中的数据(但报告写入操作成功),读取它则会立即得到一个EOF。
  • makefile基本使用方法
    在这个实验中,大量使用了函数call和函数eval来调用一些在tools/function.mk中的一些自定义语句,必须把这两个函数理解清楚
    可以参考Makefile教程(绝对经典,所有问题看这一篇足够了)
    • 函数名:dir
      格式KaTeX parse error: Expected 'EOF', got '\<' at position 6: (dir \̲<̲names>)。 ***作…(dir src/main.c foo.c) 则返回src/ 和 ./
    • 函数名:call
      格式:$(call <expression>,<parm1>,<parm2>,<parm3>…)
      作用:call函数是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,这个表达式中,你可以定义许多参数,然后你可以用call函数来向这个表达式传递参数。
      示例:reverse = $(1)$(2) foo = $(call reverse,a,b),则foo=ab.
    • 函数名:eval
      格式:$(eval text)
      作用:函数“eval”对它的参数进行展开,展开的结果作为Makefile的一部分,make可以对展开内容进行语法解析。
      示例eval函数详解
    • 函数名:patsubst
      格式:$(patsubst <pattern>,<replacement>,<text> )
      作用:模式字符串替换函数,查找 中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式,如果匹配的话,则以替换。
      示例
    • 函数名:foreach
      格式:$(foreach <var>,<list>,<text> )
      作用:把参数中的单词逐一取出放到参数所指定的变量中,然后再执行 所包含的表达式。每一次 会返回一个字符串,循环过程中, 的所返回的每个字符串会以空格分隔,最后当整个循环结束时, 所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。
      示例:names := a b c d
      files := ( f o r e a c h n , (foreach n, (foreachn,(names),$(n).o).返回:a.o b.o c.o d.o


  • GCC命令一些特殊选项
>选项作用
-fno-builtin不承认所有不是以builtin为开头的内建函数
-fno-PIC在编译时产生的代码全部使用绝对地址(-fPIC则是全部使用相对地址)
-m32生成32位程序
-gstabs生成stabs格式的调试信息,没有GDB extenstion
-nostdinc不搜索系统include目录,只在-I参数指定的目录中搜索头文件
-fno-stack-protector不在关键函数的堆栈中设置保护值(若设置为-f,则在返回地址和返回值之前都将验证这个保护值,如果缓冲区溢出,保护值不再匹配,程序就会退出)
-x language filename将filename文件类型当做指定的语言language进行编译
-E预编译

一、操作系统镜像文件ucore.img是如何一步一步生成的?

要理解该项目的makefile,首先要看懂其tools/function.mk中各条语句的功能

工具函数tools/function.mk
OBJPREFIX	:= __objs_

.SECONDEXPANSION:
# -------------------- function begin --------------------

# list all files in some directories: (#directories, #types)
# 返回返回相应directories目录下所有 类型为(types)的文件
# example:输入为listf(libs, c s),输出为libs/a.c libs/a.s
listf = $(filter $(if $(2),$(addprefix %.,$(2)),%),\
		  $(wildcard $(addsuffix $(SLASH)*,$(1))))

# get .o obj files: (#files[, packet])
# 给出文件名列表files,和软件包名称packet,返回相应文件的目标文件名称:/obj/packet/file.o
# example $(call toobj,libs/a.c libs/b.c,__obj_),生成相应的输出makefile代码为 obj/__obj_/libs/a.o obj/__obj_/libs/b.o
toobj = $(addprefix $(OBJDIR)$(SLASH)$(if $(2),$(2)$(SLASH)),\
		$(addsuffix .o,$(basename $(1))))

# get .d dependency files: (#files[, packet])
# 输入为文件名列表files和软件包名称packet,输出为相应代码文件的依赖文件名列表:obj/packet/file.d
# example $(call todep,libs/a.c libs/b.c,__obj__),对应相应的makefile代码为 __obj_/libs/a.d __obj_/libs/b.d
todep = $(patsubst %.o,%.d,$(call toobj,$(1),$(2)))

# 输出最终的目标文件完整路径名
# example $(call totarget,kernel),则对应于makefile代码为输出的最总内核目标文件为bin/kernel
totarget = $(addprefix $(BINDIR)$(SLASH),$(1))

# change $(name) to $(OBJPREFIX)$(name): (#names)
# 给定名字加上前缀$(OBJPREFIX)
# example:$(call packetname,a.o b.o),则输出为__objs_a.o __objs_b.o,若没有a.o等参数,则输出__objs_
packetname = $(if $(1),$(addprefix $(OBJPREFIX),$(1)),$(OBJPREFIX))

# cc compile template, generate rule for dep, obj: (file, cc[, flags, dir])
# 内核各个模块编译的C代码模板,用来为每一个.c或者.s文件生成编译后的目标文件
define cc_template
# 生成依目标文件的依赖文件。4个$$$$符号是因为该代码要被eval两次,并且最终生成的makefile文件继续保留对规则目标文件名的引用。
# $<:第一个依赖文件。-MT "$$(patsubst %.d,%.o,$$@) $$@":在规则中的目标文件添加%.o (这样的话,目标文件由%o %d组成)
# > $$@:将依赖规则信息输出到目标文件(%.d)中。
# "|"号表示 后面的依赖目标是order-only Prerequisites,(执行某个或某些规则,但不会引起生成目标被重新生成)
# $$$$(dir $$$$@):是一个order-only Prerequisites,其内容是是%.d文件的路径
$$(call todep,$(1),$(4)): $(1) | $$$$(dir $$$$@)
	@$(2) -I$$(dir $(1)) $(3) -MM $$< -MT "$$(patsubst %.d,%.o,$$@) $$@"> $$@
# 生成目标文件的规则。
$$(call toobj,$(1),$(4)): $(1) | $$$$(dir $$$$@)
	@echo + cc $$<
	$(V)$(2) -I$$(dir $(1)) $(3) -c $$< -o $$@
# 将所有的目标文件序列添加至ALLOBJS变量
ALLOBJS += $$(call toobj,$(1),$(4))
endef

# compile file: (#files, cc[, flags, dir])
# 用来生成最终的makefile中的所有目标文件的规则。
# 对$(1)指定的文件序列,逐个利用cc_template处理,
define do_cc_compile
$$(foreach f,$(1),$$(eval $$(call cc_template,$$(f),$(2),$(3),$(4))))
endef

# add files to packet: (#files, cc[, flags, packet, dir])
# packet和dir有区别,前者是作为__objs_系列变量的后缀,后者是目标文件的目录
# 此模板,就是真正在makefile中用来编译所有的目表文件,并生成makefile规则的模板。
define do_add_files_to_packet
# __temp_packet__用来记录所有的临时目标文件。执行后,它的值=__objs_$(4)
__temp_packet__ := $(call packetname,$(4))
# 如果__objs_$(4)这个变量没有定义,就定义一个,并让它的值=空
ifeq ($$(origin $$(__temp_packet__)),undefined)
$$(__temp_packet__) :=
endif
__temp_objs__ := $(call toobj,$(1),$(5))
$$(foreach f,$(1),$$(eval $$(call cc_template,$$(f),$(2),$(3),$(5))))
# 在__objs_$(4)这个变量的值的后面添加上$$(__temp_objs__),实际就是obj/file.o等
$$(__temp_packet__) += $$(__temp_objs__)
endef

# add objs to packet: (#objs, packet)
define do_add_objs_to_packet
__temp_packet__ := $(call packetname,$(2))
ifeq ($$(origin $$(__temp_packet__)),undefined)
$$(__temp_packet__) :=
endif
$$(__temp_packet__) += $(1)
endef

# add packets and objs to target (target, #packes, #objs[, cc, flags])
# 用来生成最终的target,在内核代码中,也就是最终的kernel和bootloader的makefile规则,$$(__temp_objs__) | $$$$(dir $$$$@) 该语句表示依赖规则的目标文件,还需要有目录的支持,如果目录不存在则应该创建,见后面规则。
define do_create_target
__temp_target__ = $(call totarget,$(1))
# 读取__objs_$(2)中的文件序列,再在最后加上$(3)返回给__temp_objs__(为什么要加$(3)???没弄明白)
__temp_objs__ = $$(foreach p,$(call packetname,$(2)),$$($$(p))) $(3)
TARGETS += $$(__temp_target__)
ifneq ($(4),)
$$(__temp_target__): $$(__temp_objs__) | $$$$(dir $$$$@)
	$(V)$(4) $(5) $$^ -o $$@
else
$$(__temp_target__): $$(__temp_objs__) | $$$$(dir $$$$@)
endif
endef

# finish all
define do_finish_all
ALLDEPS = $$(ALLOBJS:.o=.d)
$$(sort $$(dir $$(ALLOBJS)) $(BINDIR)$(SLASH) $(OBJDIR)$(SLASH)):
# 如果相应目录不存在则执行makedir -p 命令
	@$(MKDIR) $$@
endef

# 函数功能:函数“eval”是一个比较特殊的函数。使用它可以在Makefile中构造一个可变的规则结构关系(依赖关系链),其中可以使用其它变量和函数。
# 			函数“eval”对它的参数进行展开,展开的结果作为Makefile的一部分,make可以对展开内容进行语法解析。
# 			展开的结果可以包含一个新变量、目标、隐含规则或者是明确规则等。也就是说此函数的功能主要是:根据其参数的关系、结构,对它们进行替换展开。
# 返回值:函数“eval”的返回值时空,也可以说没有返回值。

# --------------------  function end  --------------------
# compile file: (#files, cc[, flags, dir])
cc_compile = $(eval $(call do_cc_compile,$(1),$(2),$(3),$(4)))

# add files to packet: (#files, cc[, flags, packet, dir])
add_files = $(eval $(call do_add_files_to_packet,$(1),$(2),$(3),$(4),$(5)))

# add objs to packet: (#objs, packet)
add_objs = $(eval $(call do_add_objs_to_packet,$(1),$(2)))

# add packets and objs to target (target, #packes, #objs, cc, [, flags])
create_target = $(eval $(call do_create_target,$(1),$(2),$(3),$(4),$(5)))

# 诸葛选取取变量__objs_$(1)中的文件序列赋值给p,然后返回以某个文件为变量名的值
read_packet = $(foreach p,$(call packetname,$(1)),$($(p)))

add_dependency = $(eval $(1): $(2))

finish_all = $(eval $(call do_finish_all))
makefile主文件
PROJ	:= challenge
EMPTY	:=
SPACE	:= $(EMPTY) $(EMPTY)
SLASH	:= /

V       := @

# try to infer the correct GCCPREFX
ifndef GCCPREFIX
GCCPREFIX := $(shell if i386-elf-objdump -i 2>&1 | grep '^elf32-i386$$' >/dev/null 2>&1; \
	then echo 'i386-elf-'; \
	elif objdump -i 2>&1 | grep 'elf32-i386' >/dev/null 2>&1; \
	then echo ''; \
	else echo "***" 1>&2; \
	echo "*** Error: Couldn't find an i386-elf version of GCC/binutils." 1>&2; \
	echo "*** Is the directory with i386-elf-gcc in your PATH?" 1>&2; \
	echo "*** If your i386-elf toolchain is installed with a command" 1>&2; \
	echo "*** prefix other than 'i386-elf-', set your GCCPREFIX" 1>&2; \
	echo "*** environment variable to that prefix and run 'make' again." 1>&2; \
	echo "*** To turn off this error, run 'gmake GCCPREFIX= ...'." 1>&2; \
	echo "***" 1>&2; exit 1; fi) 
	# 该语句根据名字判断是GCC命令的前缀
endif

# try to infer the correct QEMU
ifndef QEMU
QEMU := $(shell if which qemu-system-i386 > /dev/null; \
	then echo 'qemu-system-i386'; exit; \
	elif which i386-elf-qemu > /dev/null; \
	then echo 'i386-elf-qemu'; exit; \
	else \
	echo "***" 1>&2; \
	echo "*** Error: Couldn't find a working QEMU executable." 1>&2; \
	echo "*** Is the directory containing the qemu binary in your PATH" 1>&2; \
	echo "***" 1>&2; exit 1; fi)
endif

# eliminate default suffix rules,声明后缀依赖
.SUFFIXES: .c .S .h

# delete target files if there is an error (or make is interrupted),当make发生错误时,要删除的文件
.DELETE_ON_ERROR:

# define compiler and flags

HOSTCC		:= gcc
HOSTCFLAGS	:= -g -Wall -O2

CC		:= $(GCCPREFIX)gcc
# -fno-builtin:不使用C内建函数
# -fno-PIC:在编译时产生的代码全部使用绝对地址(-fPIC则是全部使用相对地址)
# -m32:生成32位程序
# -gstabs:生成stabs格式的调试信息,没有GDB extenstion
# -nostdinc:不搜索系统include目录,只在-I参数指定的目录中搜索头文件
# -fno-stack-protector:不在关键函数的堆栈中设置保护值(若设置为-f,则在返回地址和返回值之前都将验证这个保护值,如果缓冲区溢出,保护值不再匹配,程序就会退出)
# -x language filename:将filename文件类型当做指定的语言language进行编译
# -E :预编译
# gcc -fno-stack-protector -E -x -c /dev/null >/dev/null && echo -fno-stack-protecotr,先执行第一条命令(对dev/null用编译c语言的方式进行预编译),若成功,就输出-fno-stack-protecotr
CFLAGS	:= -fno-builtin -fno-PIC -Wall -ggdb -m32 -gstabs -nostdinc $(DEFS) 
CFLAGS	+= $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
CTYPE	:= c S

# head -n 1 filename:输出文件的第一行内容
LD      := $(GCCPREFIX)ld
# -m 指定链接时使用的模拟链接器(elf_i386)
# $(shell $(LD) -V | grep elf_i386 2>/dev/null | head -n 1)是为了获取环境支持的模拟连接器
LDFLAGS	:= -m $(shell $(LD) -V | grep elf_i386 2>/dev/null | head -n 1)
# -nostdlib:不使用标准库
LDFLAGS	+= -nostdlib

OBJCOPY := $(GCCPREFIX)objcopy
OBJDUMP := $(GCCPREFIX)objdump

COPY	:= cp
MKDIR   := mkdir -p
MV		:= mv
RM		:= rm -f
AWK		:= awk
SED		:= sed
SH		:= sh
TR		:= tr
TOUCH	:= touch -c

OBJDIR	:= obj
BINDIR	:= bin

ALLOBJS	:=
ALLDEPS	:=
TARGETS	:=

# function.mk中定义了很多有用的表达式,可以用call 来调用
include tools/function.mk

# 这里利用function.mk中定义的表达式listf(列出参数1指定目录中类型为type的文件),将其参数2固化为$(CTYPE),c和S。
listf_cc = $(call listf,$(1),$(CTYPE))

# for cc
# 参数:	$(1):#files。源代码文件名
# packet,附加编译选项,目标在obj目录下的子目录名
add_files_cc = $(call add_files,$(1),$(CC),$(CFLAGS) $(3),$(2),$(4))
create_target_cc = $(call create_target,$(1),$(2),$(3),$(CC),$(CFLAGS))

# for hostcc
add_files_host = $(call add_files,$(1),$(HOSTCC),$(HOSTCFLAGS),$(2),$(3))
create_target_host = $(call create_target,$(1),$(2),$(3),$(HOSTCC),$(HOSTCFLAGS))

# cgtype参数:1、文件序列;2、模式串;3、替换串
cgtype = $(patsubst %.$(2),%.$(3),$(1))
objfile = $(call toobj,$(1))
# 将目标文件%.o改为%.asm
asmfile = $(call cgtype,$(call toobj,$(1)),o,asm)
# 将目标文件%.o改为%.out
outfile = $(call cgtype,$(call toobj,$(1)),o,out)
# 将目标文件%.o改为%.sym
symfile = $(call cgtype,$(call toobj,$(1)),o,sym)

# for match pattern
match = $(shell echo $(2) | $(AWK) '{for(i=1;i<=NF;i++){if(match("$(1)","^"$$(i)"$$")){exit 1;}}}'; echo $$?)

# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
# include kernel/user

INCLUDE	+= libs/

CFLAGS	+= $(addprefix -I,$(INCLUDE))

LIBDIR	+= libs

# 对LIBDIR目录中每一个C或S文件,生成目标文件。
# 这里参数libs是add_files_cc的第2个,add_files的第4个,do_add_files_to_packet的第4个变量
# 实际上libs最终和__objs_组成一个变量:__objs_libs,用来记录libs下的目标文件序列
# 在这里,没有传$(3),所以flag没有附加选项
# 在这里,没有传$(4),这个参数是add_files_cc的第4个,add_files的第5个,do_add_files_to_packet的第5个
# 最终$(4)会传给toobj的$(2),因为这里没有传这个参数,因此生成obj文件路径直接是obj/file.o
$(call add_files_cc,$(call listf_cc,$(LIBDIR)),libs,)

# -------------------------------------------------------------------
# kernel

KINCLUDE	+= kern/debug/ \
			   kern/driver/ \
			   kern/trap/ \
			   kern/mm/

KSRCDIR		+= kern/init \
			   kern/libs \
			   kern/debug \
			   kern/driver \
			   kern/trap \
			   kern/mm

KCFLAGS		+= $(addprefix -I,$(KINCLUDE))

# 编译kern文件夹下的源代码,编译号的obj文件会放在obj目录下
# 同LIBDIR,kernel会和__objs_组成一个变量。而KCFLAGS是CFLAGS的附加选项
$(call add_files_cc,$(call listf_cc,$(KSRCDIR)),kernel,$(KCFLAGS))

# 依次读取__objs_kernel和__objs_libs这两个变量中的文件序列,并返回给KOBJS
KOBJS	= $(call read_packet,kernel libs)

# create kernel target
kernel = $(call totarget,kernel)

$(kernel): tools/kernel.ld

$(kernel): $(KOBJS)
	@echo + ld $@
# 使用tools/kernel.ld脚本链接所有目标文件
	$(V)$(LD) $(LDFLAGS) -T tools/kernel.ld -o $@ $(KOBJS)
	@$(OBJDUMP) -S $@ > $(call asmfile,kernel)
	@$(OBJDUMP) -t $@ | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(call symfile,kernel)

$(call create_target,kernel)

# -------------------------------------------------------------------

# create bootblock
bootfiles = $(call listf_cc,boot)
$(foreach f,$(bootfiles),$(call cc_compile,$(f),$(CC),$(CFLAGS) -Os -nostdinc))

bootblock = $(call totarget,bootblock)

$(bootblock): $(call toobj,$(bootfiles)) | $(call totarget,sign)
	@echo + ld $@
	$(V)$(LD) $(LDFLAGS) -N -e start -Ttext 0x7C00 $^ -o $(call toobj,bootblock)
	@$(OBJDUMP) -S $(call objfile,bootblock) > $(call asmfile,bootblock)
	@$(OBJDUMP) -t $(call objfile,bootblock) | $(SED) '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $(call symfile,bootblock)
	@$(OBJCOPY) -S -O binary $(call objfile,bootblock) $(call outfile,bootblock)
	@$(call totarget,sign) $(call outfile,bootblock) $(bootblock)

$(call create_target,bootblock)

# -------------------------------------------------------------------

# create 'sign' tools
$(call add_files_host,tools/sign.c,sign,sign)
$(call create_target_host,sign,sign)

# -------------------------------------------------------------------

# create ucore.img
UCOREIMG	:= $(call totarget,ucore.img)

$(UCOREIMG): $(kernel) $(bootblock)
	$(V)dd if=/dev/zero of=$@ count=10000
	$(V)dd if=$(bootblock) of=$@ conv=notrunc
	$(V)dd if=$(kernel) of=$@ seek=1 conv=notrunc

$(call create_target,ucore.img)

# >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

$(call finish_all)

IGNORE_ALLDEPS	= clean \
				  dist-clean \
				  grade \
				  touch \
				  print-.+ \
				  handin

ifeq ($(call match,$(MAKECMDGOALS),$(IGNORE_ALLDEPS)),0)
-include $(ALLDEPS)
endif

# files for grade script

TARGETS: $(TARGETS)
all: $(TARGETS)
.DEFAULT_GOAL := TARGETS

.PHONY: qemu qemu-nox debug debug-nox
lab1-mon: $(UCOREIMG)
	$(V)$(TERMINAL) -e "$(QEMU) -S -s -d in_asm -D $(BINDIR)/q.log -monitor stdio -hda $< -serial null"
	$(V)sleep 2
	$(V)$(TERMINAL) -e "gdb -q -x tools/lab1init"
debug-mon: $(UCOREIMG)
#	$(V)$(QEMU) -S -s -monitor stdio -hda $< -serial null &
	$(V)$(TERMINAL) -e "$(QEMU) -S -s -monitor stdio -hda $< -serial null"
	$(V)sleep 2
	$(V)$(TERMINAL) -e "gdb -q -x tools/moninit"
qemu-mon: $(UCOREIMG)
	$(V)$(QEMU) -monitor stdio -hda $< -serial null
qemu: $(UCOREIMG)
	$(V)$(QEMU) -parallel stdio -hda $< -serial null

qemu-nox: $(UCOREIMG)
	$(V)$(QEMU) -serial mon:stdio -hda $< -nographic
TERMINAL        :=gnome-terminal
gdb: $(UCOREIMG)
	$(V)$(QEMU) -S -s -parallel stdio -hda $< -serial null
debug: $(UCOREIMG)
	$(V)$(QEMU) -S -s -parallel stdio -hda $< -serial null &
	$(V)sleep 2
	$(V)$(TERMINAL)  -e "cgdb -q -x tools/gdbinit"
	
debug-nox: $(UCOREIMG)
	$(V)$(QEMU) -S -s -serial mon:stdio -hda $< -nographic &
	$(V)sleep 2
	$(V)$(TERMINAL) -e "gdb -q -x tools/gdbinit"

.PHONY: grade touch

GRADE_GDB_IN	:= .gdb.in
GRADE_QEMU_OUT	:= .qemu.out
HANDIN			:= proj$(PROJ)-handin.tar.gz

TOUCH_FILES		:= kern/trap/trap.c

MAKEOPTS		:= --quiet --no-print-directory

grade:
	$(V)$(MAKE) $(MAKEOPTS) clean
	$(V)$(SH) tools/grade.sh

touch:
	$(V)$(foreach f,$(TOUCH_FILES),$(TOUCH) $(f))

print-%:
	@echo $($(shell echo $(patsubst print-%,%,$@) | $(TR) [a-z] [A-Z]))

.PHONY: clean dist-clean handin packall
clean:
	$(V)$(RM) $(GRADE_GDB_IN) $(GRADE_QEMU_OUT)
	-$(RM) -r $(OBJDIR) $(BINDIR)

dist-clean: clean
	-$(RM) $(HANDIN)

handin: packall
	@echo Please visit http://learn.tsinghua.edu.cn and upload $(HANDIN). Thanks!

packall: clean
	@$(RM) -f $(HANDIN)
	@tar -czf $(HANDIN) `find . -type f -o -type d | grep -v '^\.*$$' | grep -vF '$(HANDIN)'`
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值