From bc0fa3e3ce4723f738741cd4c01be62f71634cf1 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Wed, 30 Jan 2019 19:43:45 -0500 Subject: [PATCH 01/10] =?UTF-8?q?=F0=9F=94=A5=20=E2=9A=A0=20Shuffle=20Make?= =?UTF-8?q?files=20(#87)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### Summary: - Move most targets and variables into common.mk. The only thing that remains in Makefile and template-Makefile are "parameters" to common.mk - Projects that are libraries (setups like PROS kernel and okapilib) will compile the library and link a final uploadable product against that. Rather than linking directly against all the `.o` files that the library archives, we link against libpros.a and any files not included in libpros.a inside `src/` #### Motivation: Files in projects marked as "user files" by the template are never modified - when upgrading a project, only "system files" are allowed to be modified. We'd like to be able to modify how PROS projects compile from version to version. Currently, a lot of the logic for compiling projects lives in Makefile. This PR moves as much logic as possible into the system file common.mk. I'm particularly motivated to get this done so that we can make modifications for hot-cold linking. #### Impact: User projects must manually update their Makefile to remove everything we're removing in this PR. ##### References (optional): Supporting T741 #### Test Plan: - [X] Compile kernel as a complete program - [X] Upload default program and runs correctly (sufficient to test libv5rts, kernel, and libc link correctly) - [X] Compile libpros.a - [X] Compile template - [X] Compile user program - [X] Upload default program and runs correctly (sufficient to test libv5rts, kernel, and libc link correctly) --- Makefile | 150 +++++++++++++--------------------------------- common.mk | 114 ++++++++++++++++++++++++++++++++++- template-Makefile | 99 ------------------------------ 3 files changed, 153 insertions(+), 210 deletions(-) diff --git a/Makefile b/Makefile index 521984bf9..c93c56e0f 100644 --- a/Makefile +++ b/Makefile @@ -1,71 +1,58 @@ +################################################################################ +######################### User configurable parameters ######################### +# filename extensions CEXTS:=c ASMEXTS:=s S CXXEXTS:=cpp c++ cc -WARNFLAGS=-Wall -Wpedantic - -LIBNAME=libpros -LIBAR=$(BINDIR)/$(LIBNAME).a - +# probably shouldn't modify these, but you may need them below ROOT=. FWDIR:=$(ROOT)/firmware BINDIR=$(ROOT)/bin SRCDIR=$(ROOT)/src INCDIR=$(ROOT)/include -IFI_INC=$(FWDIR)/libv5rts/sdk/vexv5/include -SDK=$(FWDIR)/libv5rts/sdk/vexv5/libv5rts.a +EXTRA_INCDIR=$(FWDIR)/libv5rts/sdk/vexv5/include -.DEFAULT_GOAL:=quick - --include ./common.mk +# Directories to be excluded from all builds +EXCLUDE_SRCDIRS+=$(SRCDIR)/tests -EXCLUDE_SRCDIRS=$(SRCDIR)/tests -EXCLUDE_FROM_LIB=$(SRCDIR)/opcontrol.cpp $(SRCDIR)/initialize.cpp $(SRCDIR)/autonomous.cpp -LIBV5RTS_EXTRACTION_DIR=$(BINDIR)/libv5rts - -TEMPLATE_DIR=$(ROOT)/template -TEMPLATE_FILES=$(ROOT)/common.mk $(FWDIR)/v5.ld $(INCDIR)/api.h $(INCDIR)/main.h $(INCDIR)/pros/*.* $(SRCDIR)/opcontrol.cpp $(SRCDIR)/initialize.cpp $(SRCDIR)/autonomous.cpp $(INCDIR)/display +WARNFLAGS+=-Wall -Wpedantic +EXTRA_CFLAGS= +EXTRA_CXXFLAGS= -INCLUDE=-iquote$(INCDIR) -iquote$(IFI_INC) +.DEFAULT_GOAL=quick -ASMSRC=$(foreach asmext,$(ASMEXTS),$(call rwildcard, $(SRCDIR),*.$(asmext), $1)) -ASMOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call ASMSRC,$1))) -CSRC=$(foreach cext,$(CEXTS),$(call rwildcard, $(SRCDIR),*.$(cext), $1)) -COBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CSRC,$1))) -CXXSRC=$(foreach cxxext,$(CXXEXTS),$(call rwildcard, $(SRCDIR),*.$(cxxext), $1)) -CXXOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CXXSRC,$1))) +# Set this to 1 to add additional rules to compile your project as a PROS library template +IS_LIBRARY:=1 +LIBNAME:=libpros +VERSION=$(shell cat $(ROOT)/version) +# EXCLUDE_SRC_FROM_LIB= $(SRCDIR)/unpublishedfile.c +EXCLUDE_SRC_FROM_LIB+=$(EXCLUDE_SRCDIRS) +# this line excludes opcontrol.c and similar files +EXCLUDE_SRC_FROM_LIB+=$(foreach file, $(SRCDIR)/opcontrol $(SRCDIR)/initialize $(SRCDIR)/autonomous,$(foreach cext,$(CEXTS),$(file).$(cext)) $(foreach cxxext,$(CXXEXTS),$(file).$(cxxext))) -GETALLOBJ=$(sort $(call ASMOBJ,$1) $(call COBJ,$1) $(call CXXOBJ,$1)) - -LIBRARIES=-L$(FWDIR) -Wl,--start-group $(wildcard $(FWDIR)/*.a) $(SDK) -lc -lm -lgcc -lstdc++ -lsupc++ -Wl,--end-group -ARCHIVE_TEXT_LIST:=$(subst $(SPACE),$(COMMA),$(notdir $(basename $(wildcard $(FWDIR)/*.a) $(SDK)))) - -ifndef OUTBIN -OUTNAME:=output -endif -OUTBIN:=$(BINDIR)/$(OUTNAME).bin -OUTELF:=$(BINDIR)/$(OUTNAME).elf -LDTIMEOBJ:=$(BINDIR)/_pros_ld_timestamp.o - -.PHONY: all clean quick library clean-library template clean-template version fix-libv5rts - -quick: $(OUTBIN) - -all: clean $(OUTBIN) +# files that get distributed to every user (beyond your source archive) - add +# whatever files you want here. This line is configured to add all header files +# that are in the the include directory get exported +TEMPLATE_FILES=$(ROOT)/common.mk $(FWDIR)/v5.ld $(INCDIR)/api.h $(INCDIR)/main.h $(INCDIR)/pros/*.* $(SRCDIR)/opcontrol.cpp $(SRCDIR)/initialize.cpp $(SRCDIR)/autonomous.cpp $(INCDIR)/display -clean: clean-library - @echo Cleaning project - -$Drm -rf $(BINDIR) +PATCHED_SDK=$(FWDIR)/libv5rts/sdk/vexv5/libv5rts.patched.a -clean-library: - @echo Cleaning libpros - -$Drm -f $(LIBAR) +EXTRA_LIB_DEPS=$(INCDIR)/api.h $(PATCHED_SDK) -library: version clean-library $(LIBAR) +################################################################################ +################################################################################ +########## Nothing below this line should be edited by typical users ########### +-include ./common.mk -version: version.py +.PHONY: $(INCDIR)/api.h +$(INCDIR)/api.h: version.py $(VV)python version.py +$(PATCHED_SDK): $(FWDIR)/libv5rts/sdk/vexv5/libv5rts.a + @echo -n "Stripping unwanted symbols from libv5rts.a " + $(call test_output,$D$(STRIP) $^ @libv5rts-strip-options.txt -o $@, $(DONE_STRING)) + template: clean-template library $(VV)mkdir -p $(TEMPLATE_DIR) @echo "Moving template files to $(TEMPLATE_DIR)" @@ -76,66 +63,13 @@ template: clean-template library @echo "Creating template" $Dprosv5 c create-template $(TEMPLATE_DIR) kernel $(shell cat $(ROOT)/version) --system "./**/*" --user "src/opcontrol.{c,cpp,cc}" --user "src/initialize.{cpp,c,cc}" --user "src/autonomous.{cpp,c,cc}" --user "include/main.{hpp,h,hh}" --user "Makefile" --target v5 --output bin/output.bin -clean-template: - -$Drm -rf $(TEMPLATE_DIR) - -fix-libv5rts: - @echo -n "Stripping unwanted symbols from libv5rts.a " - $(call test_output,$D$(STRIP) $(SDK) @libv5rts-strip-options.txt,$(DONE_STRING)) - -$(LIBAR): fix-libv5rts $(call GETALLOBJ,$(EXCLUDE_SRCDIRS) $(EXCLUDE_FROM_LIB)) +LIBV5RTS_EXTRACTION_DIR=$(BINDIR)/libv5rts +$(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRCDIRS) $(EXCLUDE_FROM_LIB)) $(EXTRA_LIB_DEPS) $(VV)mkdir -p $(LIBV5RTS_EXTRACTION_DIR) @echo -n "Extracting libv5rts " - $(call test_output,$Dcd $(LIBV5RTS_EXTRACTION_DIR) && $(AR) x ../../$(SDK),$(DONE_STRING)) - $(eval LIBV5RTS_OBJECTS := $(shell $(AR) t $(SDK))) + $(call test_output,$Dcd $(LIBV5RTS_EXTRACTION_DIR) && $(AR) x ../../$(PATCHED_SDK),$(DONE_STRING)) + $(eval LIBV5RTS_OBJECTS := $(shell $(AR) t $(PATCHED_SDK))) @echo -n "Creating $@ " - $(call test_output,$D$(AR) rcs $@ $(addprefix $(LIBV5RTS_EXTRACTION_DIR)/, $(LIBV5RTS_OBJECTS)) $(filter-out fix-libv5rts,$^),$(DONE_STRING)) -# @echo -n "Stripping non-public symbols " -# $(call test_output,$D$(OBJCOPY) -S -D -g --strip-unneeded --keep-symbols public_symbols.txt $@,$(DONE_STRING)) - -$(OUTBIN): $(OUTELF) - $(VV)mkdir -p $(dir $@) - @echo -n "Creating $@ for $(DEVICE) " - $(call test_output,$D$(OBJCOPY) $< -O binary $@,$(DONE_STRING)) - -$(OUTELF): fix-libv5rts $(call GETALLOBJ,$(EXCLUDE_SRCDIRS)) - $(call _pros_ld_timestamp) - @echo -n "Linking project with $(ARCHIVE_TEXT_LIST) " - $(call test_output,$D$(LD) $(LDFLAGS) $(filter-out fix-libv5rts,$^) $(LDTIMEOBJ) $(LIBRARIES) -o $@,$(OK_STRING)) - @echo Section sizes: - -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) - -define asm_rule -$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 - $(VV)mkdir -p $$(dir $$@) - @echo -n "Compiling $$< " - $(VV)mkdir -p $$(dir $$@) - $$(call test_output,$D$(AS) -c $(ASMFLAGS) -o $$@ $$<,$(OK_STRING)) -endef -$(foreach asmext,$(ASMEXTS),$(eval $(call asm_rule,$(asmext)))) - -define c_rule -$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 - $(VV)mkdir -p $$(dir $$@) - @echo -n "Compiling $$< " - $(VV)mkdir -p $$(dir $$@) - $$(call test_output,$D$(CC) -c $(INCLUDE) -iquote$(INCDIR)/$$(dir $$*) $(CFLAGS) $(EXTRA_CFLAGS) -o $$@ $$<,$(OK_STRING)) -endef -$(foreach cext,$(CEXTS),$(eval $(call c_rule,$(cext)))) - -define cxx_rule -$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 - $(VV)mkdir -p $$(dir $$@) - @echo -n "Compiling $$< " - $(VV)mkdir -p $$(dir $$@) - $$(call test_output,$D$(CXX) -c $(INCLUDE) -iquote$(INCDIR)/$$(dir $$*) $(CXXFLAGS) $(EXTRA_CXXFLAGS) -o $$@ $$<,$(OK_STRING)) -endef -$(foreach cxxext,$(CXXEXTS),$(eval $(call cxx_rule,$(cxxext)))) - -define _pros_ld_timestamp -@echo -n "Adding timestamp " -@# Pipe a line of code defining _PROS_COMPILE_TOOLSTAMP and _PROS_COMPILE_DIRECTORY into GCC, -@# which allows compilation from stdin. We define _PROS_COMPILE_DIRECTORY using a command line-defined macro -@# which is the pwd | sed ... | tail bit, which will grab the last 3 segments of the path and truncate it 23 characters -$(call test_output, @echo 'char const * const _PROS_COMPILE_TIMESTAMP = __DATE__ " " __TIME__; char const * const _PROS_COMPILE_DIRECTORY = PCD;' | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) -DPCD="\"`pwd | tail -c 23`\"" -o $(LDTIMEOBJ) -,$(OK_STRING)) -endef + $(call test_output,$D$(AR) rcs $@ $(addprefix $(LIBV5RTS_EXTRACTION_DIR)/, $(LIBV5RTS_OBJECTS)) $(filter-out $(EXTRA_LIB_DEPS),$^),$(DONE_STRING)) + # @echo -n "Stripping non-public symbols " + # $(call test_output,$D$(OBJCOPY) -S -D -g --strip-unneeded --keep-symbols public_symbols.txt $@,$(DONE_STRING)) diff --git a/common.mk b/common.mk index 357613a85..23bb4a1e3 100644 --- a/common.mk +++ b/common.mk @@ -10,12 +10,15 @@ WARNFLAGS+= SPACE := SPACE += COMMA := , -LNK_FLAGS = -T?%$(FWDIR)/v5.ld --gc-sections + +LIBRARIES+=$(wildcard $(FWDIR)/*.a) +wlprefix=-Wl,$(subst $(SPACE),$(COMMA),$1) +LNK_FLAGS=--gc-sections --start-group $(strip $(LIBRARIES)) -lc -lm -lgcc -lstdc++ -lsupc++ --end-group ASMFLAGS=$(MFLAGS) $(WARNFLAGS) CFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) $(GCCFLAGS) --std=gnu11 -CXXFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) -funwind-tables $(GCCFLAGS) --std=gnu++17 -LDFLAGS=$(MFLAGS) $(WARNFLAGS) -nostdlib $(subst ?%,$(SPACE),$(addprefix -Wl$(COMMA), $(LNK_FLAGS))) +CXXFLAGS=$(MFLAGS) $(CPPFLAGS) $(WARNFLAGS) -funwind-tables $(GCCFLAGS) --std=gnu++17 +LDFLAGS=$(MFLAGS) $(WARNFLAGS) -nostdlib SIZEFLAGS=-d --common NUMFMTFLAGS=--to=iec --format %.2f --suffix=B @@ -102,6 +105,111 @@ D = VV = endif +INCLUDE=$(foreach dir,$(INCDIR) $(EXTRA_INCDIR),-iquote"$(dir)") + +ASMSRC=$(foreach asmext,$(ASMEXTS),$(call rwildcard, $(SRCDIR),*.$(asmext), $1)) +ASMOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call ASMSRC,$1))) +CSRC=$(foreach cext,$(CEXTS),$(call rwildcard, $(SRCDIR),*.$(cext), $1)) +COBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CSRC, $1))) +CXXSRC=$(foreach cxxext,$(CXXEXTS),$(call rwildcard, $(SRCDIR),*.$(cxxext), $1)) +CXXOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CXXSRC,$1))) + +GETALLOBJ=$(sort $(call ASMOBJ,$1) $(call COBJ,$1) $(call CXXOBJ,$1)) + +ARCHIVE_TEXT_LIST=$(subst $(SPACE),$(COMMA),$(notdir $(basename $(LIBRARIES)))) + +ifndef OUTBIN +OUTNAME:=output +endif +OUTBIN:=$(BINDIR)/$(OUTNAME).bin +OUTELF:=$(BINDIR)/$(OUTNAME).elf +LDTIMEOBJ:=$(BINDIR)/_pros_ld_timestamp.o + +.PHONY: all clean quick + +quick: $(OUTBIN) + +all: clean $(OUTBIN) + +clean: + @echo Cleaning project + -$Drm -rf $(BINDIR) + +ifeq ($(IS_LIBRARY),1) +ifeq ($(LIBNAME),libbest) +$(errror "You should rename your library! libbest is the default library name and should be changed") +endif + +LIBAR=$(BINDIR)/$(LIBNAME).a +TEMPLATE_DIR=$(ROOT)/template + +clean-template: + @echo Cleaning $(TEMPLATE_DIR) + -$Drm -rf $(TEMPLATE_DIR) + +$(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS) + @echo -n "Creating $@ " + $(call test_output,$D$(AR) rcs $@ $^, $(DONE_STRING)) + +.PHONY: library +library: $(LIBAR) + +.PHONY: template +template: clean-template $(LIBAR) + $Dprosv5 c create-template . $(LIBNAME) $(VERSION) $(foreach file,$(TEMPLATE_FILES) $(LIBAR),--system "$(file)") --target v5 $(CREATE_TEMPLATE_FLAGS) +endif + +# if project is a library source, compile the archive and link output.elf against the archive rather than source objects +ifeq ($(IS_LIBRARY),1) +OUTELF_DEPS=$(filter-out $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)), $(call GETALLOBJ,$(EXCLUDE_SRCDIRS))) +LIBRARIES+=$(LIBAR) +else +OUTELF_DEPS=$(call GETALLOBJ,$(EXCLUDE_SRCDIRS)) +endif + +$(OUTBIN): $(OUTELF) $(BINDIR) + @echo -n "Creating $@ for $(DEVICE) " + $(call test_output,$D$(OBJCOPY) $< -O binary $@,$(DONE_STRING)) + +$(OUTELF): $(OUTELF_DEPS) $(LIBRARIES) + $(call _pros_ld_timestamp) + @echo -n "Linking project with $(ARCHIVE_TEXT_LIST) " + $(call test_output,$D$(LD) $(LDFLAGS) $(OUTELF_DEPS) $(LDTIMEOBJ) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS)) -o $@,$(OK_STRING)) + @echo Section sizes: + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +define asm_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 + $(VV)mkdir -p $$(dir $$@) + @echo -n "Compiling $$< " + $$(call test_output,$D$(AS) -c $(ASMFLAGS) -o $$@ $$<,$(OK_STRING)) +endef +$(foreach asmext,$(ASMEXTS),$(eval $(call asm_rule,$(asmext)))) + +define c_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 + $(VV)mkdir -p $$(dir $$@) + @echo -n "Compiling $$< " + $$(call test_output,$D$(CC) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CFLAGS) $(EXTRA_CFLAGS) -o $$@ $$<,$(OK_STRING)) +endef +$(foreach cext,$(CEXTS),$(eval $(call c_rule,$(cext)))) + +define cxx_rule +$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 + $(VV)mkdir -p $$(dir $$@) + @echo -n "Compiling $$< " + $$(call test_output,$D$(CXX) -c $(INCLUDE) -iquote"$(INCDIR)/$$(dir $$*)" $(CXXFLAGS) $(EXTRA_CXXFLAGS) -o $$@ $$<,$(OK_STRING)) +endef +$(foreach cxxext,$(CXXEXTS),$(eval $(call cxx_rule,$(cxxext)))) + +define _pros_ld_timestamp +@echo -n "Adding timestamp " +@# Pipe a line of code defining _PROS_COMPILE_TOOLSTAMP and _PROS_COMPILE_DIRECTORY into GCC, +@# which allows compilation from stdin. We define _PROS_COMPILE_DIRECTORY using a command line-defined macro +@# which is the pwd | tail bit, which will truncate the path to the last 23 characters +$(call test_output, $(VV)echo 'char const * const _PROS_COMPILE_TIMESTAMP = __DATE__ " " __TIME__; char const * const _PROS_COMPILE_DIRECTORY = PCD;' | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) -DPCD="\"`pwd | tail -c 23`\"" -o $(LDTIMEOBJ) -,$(OK_STRING)) +endef + # these rules are for build-compile-commands, which just print out sysroot information cc-sysroot: @echo | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) --verbose -o /dev/null - diff --git a/template-Makefile b/template-Makefile index 87f605d8c..9de3a3fef 100644 --- a/template-Makefile +++ b/template-Makefile @@ -36,102 +36,3 @@ TEMPLATE_FILES=$(INCDIR)/**/*.h $(INCDIR)/**/*.hpp ################################################################################ ########## Nothing below this line should be edited by typical users ########### -include ./common.mk - -INCLUDE=-iquote$(INCDIR) - -ASMSRC=$(foreach asmext,$(ASMEXTS),$(call rwildcard, $(SRCDIR),*.$(asmext), $1)) -ASMOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call ASMSRC,$1))) -CSRC=$(foreach cext,$(CEXTS),$(call rwildcard, $(SRCDIR),*.$(cext), $1)) -COBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CSRC, $1))) -CXXSRC=$(foreach cxxext,$(CXXEXTS),$(call rwildcard, $(SRCDIR),*.$(cxxext), $1)) -CXXOBJ=$(addprefix $(BINDIR)/,$(patsubst $(SRCDIR)/%,%.o,$(call CXXSRC,$1))) - -GETALLOBJ=$(sort $(call ASMOBJ,$1) $(call COBJ,$1) $(call CXXOBJ,$1)) - -LIBRARIES=-L$(FWDIR) -Wl,--start-group $(wildcard $(FWDIR)/*.a) -lc -lm -lgcc -lstdc++ -lsupc++ -Wl,--end-group -ARCHIVE_TEXT_LIST:=$(subst $(SPACE),$(COMMA),$(notdir $(basename $(wildcard $(FWDIR)/*.a)))) - -ifndef OUTBIN -OUTNAME:=output -endif -OUTBIN:=$(BINDIR)/$(OUTNAME).bin -OUTELF:=$(BINDIR)/$(OUTNAME).elf -LDTIMEOBJ:=$(BINDIR)/_pros_ld_timestamp.o - -.PHONY: all clean quick - -quick: $(OUTBIN) - -all: clean $(OUTBIN) - -clean: - @echo Cleaning project - -$Drm -rf $(BINDIR) - -$(OUTBIN): $(OUTELF) $(BINDIR) - @echo -n "Creating $@ for $(DEVICE) " - $(call test_output,$D$(OBJCOPY) $< -O binary $@,$(DONE_STRING)) - -$(OUTELF): $(call GETALLOBJ,$(EXCLUDE_SRCDIRS)) - $(call _pros_ld_timestamp) - @echo -n "Linking project with $(ARCHIVE_TEXT_LIST) " - $(call test_output,$D$(LD) $(LDFLAGS) $^ $(LDTIMEOBJ) $(LIBRARIES) -o $@,$(OK_STRING)) - @echo Section sizes: - -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) - -define asm_rule -$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 - $(VV)mkdir -p $$(dir $$@) - @echo -n "Compiling $$< " - $$(call test_output,$D$(AS) -c $(ASMFLAGS) -o $$@ $$<,$(OK_STRING)) -endef -$(foreach asmext,$(ASMEXTS),$(eval $(call asm_rule,$(asmext)))) - -define c_rule -$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 - $(VV)mkdir -p $$(dir $$@) - @echo -n "Compiling $$< " - $$(call test_output,$D$(CC) -c $(INCLUDE) -iquote$(INCDIR)/$$(dir $$*) $(CFLAGS) $(EXTRA_CFLAGS) -o $$@ $$<,$(OK_STRING)) -endef -$(foreach cext,$(CEXTS),$(eval $(call c_rule,$(cext)))) - -define cxx_rule -$(BINDIR)/%.$1.o: $(SRCDIR)/%.$1 - $(VV)mkdir -p $$(dir $$@) - @echo -n "Compiling $$< " - $$(call test_output,$D$(CXX) -c $(INCLUDE) -iquote$(INCDIR)/$$(dir $$*) $(CXXFLAGS) $(EXTRA_CXXFLAGS) -o $$@ $$<,$(OK_STRING)) -endef -$(foreach cxxext,$(CXXEXTS),$(eval $(call cxx_rule,$(cxxext)))) - -define _pros_ld_timestamp -@echo -n "Adding timestamp " -@# Pipe a line of code defining _PROS_COMPILE_TOOLSTAMP and _PROS_COMPILE_DIRECTORY into GCC, -@# which allows compilation from stdin. We define _PROS_COMPILE_DIRECTORY using a command line-defined macro -@# which is the pwd | tail bit, which will truncate the path to the last 23 characters -$(call test_output, $(VV)echo 'char const * const _PROS_COMPILE_TIMESTAMP = __DATE__ " " __TIME__; char const * const _PROS_COMPILE_DIRECTORY = PCD;' | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) -DPCD="\"`pwd | tail -c 23`\"" -o $(LDTIMEOBJ) -,$(OK_STRING)) -endef - - -ifeq ($(IS_LIBRARY),1) -ifeq ($(LIBNAME),libbest) -$(errror "You should rename your library! libbest is the default library name and should be changed") -endif - -LIBAR=$(BINDIR)/$(LIBNAME).a -TEMPLATE_DIR=$(ROOT)/template - -clean-template: - @echo Cleaning $(TEMPLATE_DIR) - -$Drm -rf $(TEMPLATE_DIR) - -$(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) - @echo -n "Creating $@ " - $(call test_output,$D$(AR) rcs $@ $^, $(DONE_STRING)) - -.PHONY: library -library: $(LIBAR) - -.PHONY: template -template: clean-template $(LIBAR) - $Dprosv5 c create-template . $(LIBNAME) $(VERSION) $(foreach file,$(TEMPLATE_FILES) $(LIBAR),--system "$(file)") --target v5 -endif From f34a219cb49a6b5a8e81b6852abe4c84efa975d0 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Wed, 6 Feb 2019 22:23:22 -0500 Subject: [PATCH 02/10] Fix cp from old kernel Makefile to new refactored one --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index c93c56e0f..21dfc1af1 100644 --- a/Makefile +++ b/Makefile @@ -64,12 +64,12 @@ template: clean-template library $Dprosv5 c create-template $(TEMPLATE_DIR) kernel $(shell cat $(ROOT)/version) --system "./**/*" --user "src/opcontrol.{c,cpp,cc}" --user "src/initialize.{cpp,c,cc}" --user "src/autonomous.{cpp,c,cc}" --user "include/main.{hpp,h,hh}" --user "Makefile" --target v5 --output bin/output.bin LIBV5RTS_EXTRACTION_DIR=$(BINDIR)/libv5rts -$(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRCDIRS) $(EXCLUDE_FROM_LIB)) $(EXTRA_LIB_DEPS) +$(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS) $(VV)mkdir -p $(LIBV5RTS_EXTRACTION_DIR) @echo -n "Extracting libv5rts " $(call test_output,$Dcd $(LIBV5RTS_EXTRACTION_DIR) && $(AR) x ../../$(PATCHED_SDK),$(DONE_STRING)) $(eval LIBV5RTS_OBJECTS := $(shell $(AR) t $(PATCHED_SDK))) @echo -n "Creating $@ " - $(call test_output,$D$(AR) rcs $@ $(addprefix $(LIBV5RTS_EXTRACTION_DIR)/, $(LIBV5RTS_OBJECTS)) $(filter-out $(EXTRA_LIB_DEPS),$^),$(DONE_STRING)) - # @echo -n "Stripping non-public symbols " - # $(call test_output,$D$(OBJCOPY) -S -D -g --strip-unneeded --keep-symbols public_symbols.txt $@,$(DONE_STRING)) + $(call test_output,$D$(AR) rcs $@ $(addprefix $(LIBV5RTS_EXTRACTION_DIR)/, $(LIBV5RTS_OBJECTS)) $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)),$(DONE_STRING)) +# @echo -n "Stripping non-public symbols " +# $(call test_output,$D$(OBJCOPY) -S -D -g --strip-unneeded --keep-symbols public_symbols.txt $@,$(DONE_STRING)) From ad0f87c95dddaf726ff511737f807a33a13eef1c Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Sun, 10 Feb 2019 15:32:08 -0500 Subject: [PATCH 03/10] =?UTF-8?q?=F0=9F=91=B7=E2=80=8D=E2=99=82=EF=B8=8F?= =?UTF-8?q?=20Add=20Azure=20Pipelines=20for=20building=20templates=20(#94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### Summary: Add Azure Pipelines for building templates #### Motivation: It'd be nice to have standard CI builds of the kernel ##### References (optional): #### Test Plan: - [x] It build --- README.md | 2 ++ azure-pipelines.yml | 50 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 azure-pipelines.yml diff --git a/README.md b/README.md index 8946aa66f..3e49b161a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # PROS Kernel for the VEX V5 Brain +[![Build Status](https://dev.azure.com/purdue-acm-sigbots/Kernel/_apis/build/status/purduesigbots.pros?branchName=develop)](https://dev.azure.com/purdue-acm-sigbots/Kernel/_build/latest?definitionId=5&branchName=develop) + ### What is PROS? PROS is a lightweight and fast alternative open source operating system for the VEX V5 Brain. PROS is built with developers in mind and with a focus on providing an environment for industry-applicable experience. diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 000000000..0442258cf --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,50 @@ +jobs: +- job: BuildTemplate + pool: + vmImage: 'ubuntu-16.04' + steps: + - task: InstallSSHKey@0 + inputs: + sshKeySecureFile: id_sigbot_github_azure_devops + hostName: $(gh.knownhosts) + sshPublicKey: $(gh.publickey) + - checkout: self + - bash: | + sudo add-apt-repository ppa:team-gcc-arm-embedded/ppa + sudo apt-get update + sudo apt-get install gcc-arm-embedded + displayName: Install gcc-arm-embedded + - task: UsePythonVersion@0 + inputs: + addToPath: true + versionSpec: '3.6' + - task: PipAuthenticate@0 + inputs: + artifactFeeds: 'pros-cli' + - bash: pip install pros-cli-v5 + displayName: Install CLI + - bash: | + make template + make + mkdir -p artifacts + cp template/*.zip artifacts + displayName: Build template + - bash: | + echo "##vso[build.UpdateBuildNumber]`cat version`" + echo "##vso[task.setvariable variable=KernelVersion]`cat version`" + displayName: Update Build Number + - task: PublishPipelineArtifact@0 + inputs: + targetPath: artifacts + artifactName: template + condition: succeeded() + # - task: UniversalPackages@0 + # inputs: + # command: publish + # publishDirectory: artifacts + # vstsFeedPublish: 'pros-depot-nightly' + # vstsFeedPackagePublish: 'kernel' + # versionOption: custom + # versionPublish: $(KernelVersion) + # packagePublishDescription: 'CI Build of Kernel' + # condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['Build.SourceBranch'], 'refs/heads/develop'))) From 449e8b421145ee6ecb5c6fa05d3ea3829dbbff6a Mon Sep 17 00:00:00 2001 From: Alex Brooke Date: Mon, 11 Feb 2019 18:28:11 -0600 Subject: [PATCH 04/10] =?UTF-8?q?=F0=9F=90=9B=20Refactor=20task=5Fnotify?= =?UTF-8?q?=5Fwhen=5Fdeleting=20to=20support=20task=5Fto=5Fnotify=20dying?= =?UTF-8?q?=20before=20target=5Ftask=20(#100)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### Summary: - Increments `configNUM_THREAD_LOCAL_STORAGE_POINTERS` again - Adds another linked list to thread local storage that will keep track of the tasks to whose death events `task_to_notify` is subscribed - When a task dies, the `task_delete_hook` now iterates through the task's list of subscriptions and removes references to itself from the subscriptions' lists of subscribers #### Motivation: Previously, the case in which `task_to_notify` dies before `target_task` was undefined behavior, because `target_task` would attempt to notify `task_to_notify` even if it's already been cleaned up. The naive solution of checking the `task_to_notify`'s state directly would not have worked because in certain cases (as with the competition tasks), the TCB can be reused. More information regarding the motivation behind this change can be found at #86, OkapiLib/OkapiLib#249, and OkapiLib/OkapiLib#321 ##### References (optional): Closes #86 #### Test Plan: - [x] execute test plan in src/tests/task_notify_when_deleting.c (regression test) (the following are adapted from https://github.com/purduesigbots/pros/pull/100#issuecomment-461282903. thanks @Octogonapus) - [x] delete `task_to_notify` and then delete `target_task`, verify nothing goes horrendously wrong - [x] repeat previous test with OkapiLib where an internal task is the `task_to_notify` #### Commits: * begin task_notify_when_deleting refactor * add nullcheck needed to check whether subscriptions_list is null in unsubscribe_hook_cb to handle the "normal operation" case, where target_task dies before task_to_notify * delete subscriptions list anyway * look for correct task in subscriptions_ll * mutex guard task_notify_when_deleting functions, cleanup includes * stick with one method of initializing mutex * Revert "stick with one method of initializing mutex" This reverts commit 154b969872b41e7b935bfd32d7ec3d751306042f. * stick with the other method of initializing mutex --- include/pros/apix.h | 2 - include/rtos/FreeRTOSConfig.h | 2 +- src/rtos/task_notify_when_deleting.c | 77 +++++++++++++++++++++++++--- src/system/rtos_hooks.c | 3 ++ 4 files changed, 73 insertions(+), 11 deletions(-) diff --git a/include/pros/apix.h b/include/pros/apix.h index 747447c03..ec2712e26 100644 --- a/include/pros/apix.h +++ b/include/pros/apix.h @@ -60,8 +60,6 @@ bool task_abort_delay(task_t task); * task_notify_ext(task_to_notify, value, action, NULL) when target_task is * deleted. * - * NOTE: This facility does not support the case when task_to_notify - * dies before target_task * * \param target_task * The task being watched for deletion diff --git a/include/rtos/FreeRTOSConfig.h b/include/rtos/FreeRTOSConfig.h index 2f1e382b9..b723c10c8 100644 --- a/include/rtos/FreeRTOSConfig.h +++ b/include/rtos/FreeRTOSConfig.h @@ -141,7 +141,7 @@ #define configUSE_NEWLIB_REENTRANT 1 #define configSTACK_DEPTH_TYPE size_t -#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 1 +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 2 /* Include the query-heap CLI command to query the free heap space. */ #define configINCLUDE_QUERY_HEAP_COMMAND 1 diff --git a/src/rtos/task_notify_when_deleting.c b/src/rtos/task_notify_when_deleting.c index 7a277e2d8..eae98ac48 100644 --- a/src/rtos/task_notify_when_deleting.c +++ b/src/rtos/task_notify_when_deleting.c @@ -1,10 +1,20 @@ +#include "kapi.h" #include "common/linkedlist.h" -#include "rtos/task.h" + +// NOTE: can't just include task.h because of redefinition that goes on in kapi +// include chain, so we just prototype what we need here +void *pvTaskGetThreadLocalStoragePointer( task_t xTaskToQuery, int32_t xIndex ); +void vTaskSetThreadLocalStoragePointer( task_t xTaskToSet, int32_t xIndex, void *pvValue ); + #include "rtos/tcb.h" -// This increments configNUM_THREAD_LOCAL_STORAGE_POINTERS by 1 +// This increments configNUM_THREAD_LOCAL_STORAGE_POINTERS by 2 + +#define SUBSCRIBERS_TLSP_IDX 0 +#define SUBSCRIPTIONS_TLSP_IDX 1 -#define TLSP_IDX 0 +static static_sem_s_t task_notify_when_deleting_mutex_buf; +static mutex_t task_notify_when_deleting_mutex; struct notify_delete_action { task_t task_to_notify; @@ -36,20 +46,51 @@ static struct notify_delete_action* _find_task(linked_list_s_t* ll, task_t task) return args.found_action; } +void task_notify_when_deleting_init() { + task_notify_when_deleting_mutex = mutex_create_static(&task_notify_when_deleting_mutex_buf); +} + void task_notify_when_deleting(task_t target_task, task_t task_to_notify, uint32_t value, notify_action_e_t notify_action) { task_to_notify = (task_to_notify == NULL) ? pxCurrentTCB : task_to_notify; target_task = (target_task == NULL) ? pxCurrentTCB : target_task; - // It doesn't make sense for a task to notify itself, and make sure that neither task is NULL (implying that scheduler hasn't started yet) + // It doesn't make sense for a task to notify itself, and make sure that + // neither task is NULL (implying that scheduler hasn't started yet) if (task_to_notify == target_task || !task_to_notify || !target_task) { return; } - linked_list_s_t* target_ll = pvTaskGetThreadLocalStoragePointer(target_task, TLSP_IDX); + mutex_take(task_notify_when_deleting_mutex, TIMEOUT_MAX); + + // task_to_notify maintains a list of the tasks whose deletion it cares about. + // This will allow us to unsubscribe from notification if/when task_to_notify + // is deleted + linked_list_s_t* subscriptions_ll = pvTaskGetThreadLocalStoragePointer(task_to_notify, SUBSCRIPTIONS_TLSP_IDX); + if (subscriptions_ll == NULL) { + subscriptions_ll = linked_list_init(); + vTaskSetThreadLocalStoragePointer(task_to_notify, SUBSCRIPTIONS_TLSP_IDX, subscriptions_ll); + } + if (subscriptions_ll != NULL) { + // check whether task_to_notify is already subscribed to target_task. if so, + // do nothing + ll_node_s_t* it = subscriptions_ll->head; + bool found = false; + while (it != NULL && !found) { + found = it->payload.data == target_task; + it = it->next; + } + if (!found) { + linked_list_prepend_data(subscriptions_ll, target_task); + } + } + + // similarly, target_task maintains a list of the tasks it needs to notify + // when being deleted + linked_list_s_t* target_ll = pvTaskGetThreadLocalStoragePointer(target_task, SUBSCRIBERS_TLSP_IDX); if (target_ll == NULL) { target_ll = linked_list_init(); - vTaskSetThreadLocalStoragePointer(target_task, TLSP_IDX, target_ll); + vTaskSetThreadLocalStoragePointer(target_task, SUBSCRIBERS_TLSP_IDX, target_ll); } if (target_ll != NULL) { @@ -72,6 +113,7 @@ void task_notify_when_deleting(task_t target_task, task_t task_to_notify, action->value = value; } } + mutex_give(task_notify_when_deleting_mutex); } // NOTE: this code is untested, probably works, but also has a terrible name (task_notify_when_deleting_unsubscribe) @@ -93,6 +135,15 @@ void task_notify_when_deleting(task_t target_task, task_t task_to_notify, // } // } +static void unsubscribe_hook_cb(ll_node_s_t* node, void* task_to_remove) { + task_t subscription = node->payload.data; + + linked_list_s_t* subscriptions_list = pvTaskGetThreadLocalStoragePointer(subscription, SUBSCRIBERS_TLSP_IDX); + if (subscriptions_list != NULL) { + linked_list_remove_data(subscriptions_list, task_to_remove); + } +} + static void delete_hook_cb(ll_node_s_t* node, void* ignore) { struct notify_delete_action* action = node->payload.data; if (action != NULL) { @@ -103,10 +154,20 @@ static void delete_hook_cb(ll_node_s_t* node, void* ignore) { } void task_notify_when_deleting_hook(task_t task) { - linked_list_s_t* ll = pvTaskGetThreadLocalStoragePointer(task, TLSP_IDX); + mutex_take(task_notify_when_deleting_mutex, TIMEOUT_MAX); + // if this task was subscribed to any other task deletion events, unsubscribe + linked_list_s_t* ll = pvTaskGetThreadLocalStoragePointer(task, SUBSCRIPTIONS_TLSP_IDX); + if (ll != NULL) { + linked_list_foreach(ll, unsubscribe_hook_cb, task); + linked_list_free(ll); + vTaskSetThreadLocalStoragePointer(task, SUBSCRIPTIONS_TLSP_IDX, NULL); + } + // notify subscribed tasks of this task's deletion + ll = pvTaskGetThreadLocalStoragePointer(task, SUBSCRIBERS_TLSP_IDX); if (ll != NULL) { linked_list_foreach(ll, delete_hook_cb, NULL); linked_list_free(ll); - vTaskSetThreadLocalStoragePointer(task, TLSP_IDX, NULL); // for good measure + vTaskSetThreadLocalStoragePointer(task, SUBSCRIBERS_TLSP_IDX, NULL); // for good measure } + mutex_give(task_notify_when_deleting_mutex); } diff --git a/src/system/rtos_hooks.c b/src/system/rtos_hooks.c index c3c4824c0..2b667e629 100644 --- a/src/system/rtos_hooks.c +++ b/src/system/rtos_hooks.c @@ -44,6 +44,9 @@ void rtos_initialize() { portDISABLE_INTERRUPTS(); vPortInstallFreeRTOSVectorTable(); + + void task_notify_when_deleting_init(); + task_notify_when_deleting_init(); } extern void FreeRTOS_Tick_Handler(void); From bc1f4cb76e271603176069c5d46c14cae2032d64 Mon Sep 17 00:00:00 2001 From: Jerrylum Date: Sun, 17 Feb 2019 00:55:17 +0800 Subject: [PATCH 05/10] =?UTF-8?q?=F0=9F=90=9B=20Add=20LLEMU=20read=20butto?= =?UTF-8?q?ns=20nullcheck=20(#107)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### Summary: Someone wrote LLEMU overnight and didn't sleep. So he forgot to add `nullcheck` in method `lcd_read_buttons`. #### Motivation: Add it. ##### References (optional): Closes #106 #### Test Plan: - [x] try to use `pros::lcd::read_buttons()` before initialize the GUI - [x] try to use `pros::c::lcd_read_buttons()` before initialize the GUI --- src/display/llemu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/display/llemu.c b/src/display/llemu.c index fbe07bb5b..8b0d13910 100644 --- a/src/display/llemu.c +++ b/src/display/llemu.c @@ -300,5 +300,9 @@ bool lcd_register_btn2_cb(lcd_btn_cb_fn_t cb) { } uint8_t lcd_read_buttons(void) { + if (!lcd_is_initialized()) { + errno = ENXIO; + return 0; + } return _lcd_read_buttons(_llemu_lcd); } From a699d93aff249fc6feb3d81aa0ccd648b18403d2 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Sun, 17 Feb 2019 13:04:05 -0500 Subject: [PATCH 06/10] =?UTF-8?q?=F0=9F=91=B7=E2=80=8D=E2=99=82=EF=B8=8F?= =?UTF-8?q?=20Re-order=20make=20execution=20after=20updating=20build=20num?= =?UTF-8?q?ber=20(#111)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### Summary: ``` make template make ``` would cause the version to be updated to a dirty commit version, which would then get set as the build number (despite being a commit build) This change does ``` make template (Update Build number) make ``` #### Motivation: So that we don't see a dirty version ##### References (optional): #### Test Plan: - [x] Look at Pipeline build number ![image](https://user-images.githubusercontent.com/5461357/52889533-70220a80-314e-11e9-9972-1342bb7303a2.png) #### Commits: * Re-order make execution after updating build number So that we don't see a dirty version * Try including PR ID in version * print environ * Fix it --- azure-pipelines.yml | 4 +++- version.py | 14 ++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0442258cf..c744a7975 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -25,7 +25,6 @@ jobs: displayName: Install CLI - bash: | make template - make mkdir -p artifacts cp template/*.zip artifacts displayName: Build template @@ -33,6 +32,9 @@ jobs: echo "##vso[build.UpdateBuildNumber]`cat version`" echo "##vso[task.setvariable variable=KernelVersion]`cat version`" displayName: Update Build Number + - bash: | + make + displayName: Build binaries - task: PublishPipelineArtifact@0 inputs: targetPath: artifacts diff --git a/version.py b/version.py index c34b8d206..ade03af0e 100644 --- a/version.py +++ b/version.py @@ -1,16 +1,22 @@ from __future__ import print_function import subprocess import io +import os try: v = subprocess.check_output(['git', 'describe', '--dirty', '--abbrev']).decode().strip() if '-' in v: bv = v[:v.index('-')] bv = bv[:bv.rindex('.') + 1] + str(int(bv[bv.rindex('.') + 1:]) + 1) - sempre = 'dirty' if v.endswith('-dirty') else 'commit' - pippre = 'alpha' if v.endswith('-dirty') else 'pre' - build = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode().strip() - number_since = subprocess.check_output(['git', 'rev-list', v[:v.index('-')] + '..HEAD', '--count']).decode().strip() + if os.environ.get('SYSTEM_PULLREQUEST_PULLREQUESTNUMBER', None): # for Azure Pipelines PR builder + sempre = 'pr{}'.format(os.environ.get('SYSTEM_PULLREQUEST_PULLREQUESTNUMBER')) + build = os.environ.get('BUILD_BUILDID') + else: + sempre = 'dirty' if v.endswith('-dirty') else 'commit' + # pippre = 'alpha' if v.endswith('-dirty') else 'pre' + build = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode().strip() + number_since = subprocess.check_output(['git', 'rev-list', v[:v.index('-')] + '..HEAD', '--count']).decode().strip() + build = "{}+{}".format(number_since, build) semver = bv + '-' + sempre + '+' + build else: semver = v From 728dcb1a4f8bb693bf3b71d6d0369033bad848ab Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Sun, 17 Feb 2019 13:39:35 -0500 Subject: [PATCH 07/10] =?UTF-8?q?=E2=9C=A8=20Add=20=F0=9F=94=A5/=E2=9D=84?= =?UTF-8?q?=20linking=20(#89)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### Summary: Adds new form of linking that I call hot/cold. This method of linking creates two binary images that get uploaded to the V5. One is the "cold" image that contains any archives (e.g. libpros and okapilib) the project is using and libstdc++ and contains all functions the user could invoke from these libraries. User code is compiled and linked against this "cold" binary to form a "hot" binary. Using V5 file links, the cold binary can be uploaded once and only the hot binary can be uploaded at every compilation. For a base project with okapilib that was originally ~471KB, the cold binary was approximately 1MB and the hot binary was 1.5 KB. When applying compression, the cold binary gets cut to 500 KB and the hot binary to <1KB (0.2% of the original size for a typical upload). The cold binary would take a few seconds to upload when wired and the hot binary would take less than a second even when uploaded wirelessly (ignoring channel transfer time). #### Motivation: This will make upload times shorter, especially wirelessly. #### Impact: - The default binary name has changed from output.bin -> monolith.bin - Hot/cold linking will start off disabled by default and can be enabled with `USE_PACKAGE=1` in the Makefile (or at the command line) ##### References (optional): purduesigbots/pros-cli#46 #### Test Plan: - [x] Kernel - [X] Compile hot/cold - [X] Upload hot/cold - [x] Compile monolith - [x] Upload monolith - [x] Base project - [x] Compile hot/cold (1.5KB/983KB) - [x] Upload hot/cold - [x] Compile monolith (425KB) - [x] Upload monolith - [x] Okapi Clawbot - [x] Compile hot/cold (3.71KB/983KB) - [x] Upload hot/cold - [x] Compile monolith (425KB) - [x] Upload monolith - [x] Rogers - [x] Compile hot/cold - [x] Upload hot/cold - [x] Compile monolith - [x] Upload monolith - [x] Forkner - [x] Compile hot/cold (55.1KB/983KB w/o libforkner; 26.9KB/0.99MB w/libforkner) - [x] Upload hot/cold - [x] Compile monolith (537KB) - [x] Upload monolith - [x] okapilib@4.0.0 - [x] Compile hot/cold - [x] Run hot/cold * Binary sizes are uncompressed #### Commits: * Fix libpros compilation * Add initial version of hot-cold linking from hot-cold2 and hot-cold * Fix project.pros for kernel and generation * Use macros for hot magic words * Use memset instead of assembly loop This is what newlib crt0 does anyway https://github.com/bminor/newlib/blob/9a5abcc896bde48ae72fd62fe43a2307663d8ad5/libgloss/arm/crt0.S#L251-L271 * Remove printfs * Turn off USE_PACKAGE by default, error when USE_PACKAGE isn't defined * Remove old libar before creating * Strip symbols, refactor to supress warnings * Fix typo * Zero (s)bss sections with asm - Using the C compiler optimized and used symbols I couldn't figure out. Directly using assembly made it work just fine. * Remove unnncessary symbol stripping * Fix timestamp/directory banners * Check if linked file exists using VEX API V5 doesn't clear out DDR, so if you run hot/cold then monolith, PROS will see the magic bytes still present, but will not run correctly because everything in the "cold" image isn't the way the hot image is expecting. * Compare SDK addr to COLD_MEMORY addr * Go back to compiled C * Add comment, rm test goal * Move migration check so it works * Linting --- Makefile | 14 +- common.mk | 67 +++++-- firmware/v5-common.ld | 9 + firmware/v5-hot.ld | 236 +++++++++++++++++++++++ firmware/v5.ld | 77 ++++---- include/system/hot.h | 14 ++ include/system/user_functions.h | 5 + include/system/user_functions/c_list.h | 9 + include/system/user_functions/cpp_list.h | 9 + include/system/user_functions/list.h | 6 + project.pros | 2 +- src/system/cpp_support.cpp | 16 -- src/system/dev/ser_daemon.c | 11 +- src/system/hot.c | 77 ++++++++ src/system/main.c | 3 + src/system/system_daemon.c | 53 +---- src/system/user_functions.c | 44 +++++ template-Makefile | 3 + 18 files changed, 533 insertions(+), 122 deletions(-) create mode 100644 firmware/v5-common.ld create mode 100644 firmware/v5-hot.ld create mode 100644 include/system/hot.h create mode 100644 include/system/user_functions.h create mode 100644 include/system/user_functions/c_list.h create mode 100644 include/system/user_functions/cpp_list.h create mode 100644 include/system/user_functions/list.h create mode 100644 src/system/hot.c create mode 100644 src/system/user_functions.c diff --git a/Makefile b/Makefile index 21dfc1af1..331590e6a 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ EXTRA_CFLAGS= EXTRA_CXXFLAGS= .DEFAULT_GOAL=quick +USE_PACKAGE:=0 # Set this to 1 to add additional rules to compile your project as a PROS library template IS_LIBRARY:=1 @@ -34,7 +35,9 @@ EXCLUDE_SRC_FROM_LIB+=$(foreach file, $(SRCDIR)/opcontrol $(SRCDIR)/initialize $ # files that get distributed to every user (beyond your source archive) - add # whatever files you want here. This line is configured to add all header files # that are in the the include directory get exported -TEMPLATE_FILES=$(ROOT)/common.mk $(FWDIR)/v5.ld $(INCDIR)/api.h $(INCDIR)/main.h $(INCDIR)/pros/*.* $(SRCDIR)/opcontrol.cpp $(SRCDIR)/initialize.cpp $(SRCDIR)/autonomous.cpp $(INCDIR)/display +TEMPLATE_FILES=$(ROOT)/common.mk $(FWDIR)/v5.ld $(FWDIR)/v5-common.ld $(FWDIR)/v5-hot.ld +TEMPLATE_FILES+= $(INCDIR)/api.h $(INCDIR)/main.h $(INCDIR)/pros/*.* $(INCDIR)/display +TEMPLATE_FILES+= $(SRCDIR)/opcontrol.cpp $(SRCDIR)/initialize.cpp $(SRCDIR)/autonomous.cpp PATCHED_SDK=$(FWDIR)/libv5rts/sdk/vexv5/libv5rts.patched.a @@ -53,6 +56,12 @@ $(PATCHED_SDK): $(FWDIR)/libv5rts/sdk/vexv5/libv5rts.a @echo -n "Stripping unwanted symbols from libv5rts.a " $(call test_output,$D$(STRIP) $^ @libv5rts-strip-options.txt -o $@, $(DONE_STRING)) + +CREATE_TEMPLATE_ARGS=--system "./**/*" +CREATE_TEMPLATE_ARGS+=--user "src/opcontrol.{c,cpp,cc}" --user "src/initialize.{cpp,c,cc}" --user "src/autonomous.{cpp,c,cc}" --user "include/main.{hpp,h,hh}" --user "Makefile" +CREATE_TEMPLATE_ARGS+=--target v5 +CREATE_TEMPLATE_ARGS+=--output bin/monolith.bin --cold_output bin/cold.package.bin --hot_output bin/hot.package.bin --cold_addr 58720256 --hot_addr 125829120 + template: clean-template library $(VV)mkdir -p $(TEMPLATE_DIR) @echo "Moving template files to $(TEMPLATE_DIR)" @@ -61,7 +70,7 @@ template: clean-template library $Dcp $(LIBAR) $(TEMPLATE_DIR)/firmware $Dcp $(ROOT)/template-Makefile $(TEMPLATE_DIR)/Makefile @echo "Creating template" - $Dprosv5 c create-template $(TEMPLATE_DIR) kernel $(shell cat $(ROOT)/version) --system "./**/*" --user "src/opcontrol.{c,cpp,cc}" --user "src/initialize.{cpp,c,cc}" --user "src/autonomous.{cpp,c,cc}" --user "include/main.{hpp,h,hh}" --user "Makefile" --target v5 --output bin/output.bin + $Dprosv5 c create-template $(TEMPLATE_DIR) kernel $(shell cat $(ROOT)/version) $(CREATE_TEMPLATE_ARGS) LIBV5RTS_EXTRACTION_DIR=$(BINDIR)/libv5rts $(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS) @@ -69,6 +78,7 @@ $(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS) @echo -n "Extracting libv5rts " $(call test_output,$Dcd $(LIBV5RTS_EXTRACTION_DIR) && $(AR) x ../../$(PATCHED_SDK),$(DONE_STRING)) $(eval LIBV5RTS_OBJECTS := $(shell $(AR) t $(PATCHED_SDK))) + -$Drm -f $@ @echo -n "Creating $@ " $(call test_output,$D$(AR) rcs $@ $(addprefix $(LIBV5RTS_EXTRACTION_DIR)/, $(LIBV5RTS_OBJECTS)) $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)),$(DONE_STRING)) # @echo -n "Stripping non-public symbols " diff --git a/common.mk b/common.mk index 23bb4a1e3..808a997ef 100644 --- a/common.mk +++ b/common.mk @@ -118,18 +118,31 @@ GETALLOBJ=$(sort $(call ASMOBJ,$1) $(call COBJ,$1) $(call CXXOBJ,$1)) ARCHIVE_TEXT_LIST=$(subst $(SPACE),$(COMMA),$(notdir $(basename $(LIBRARIES)))) -ifndef OUTBIN -OUTNAME:=output -endif -OUTBIN:=$(BINDIR)/$(OUTNAME).bin -OUTELF:=$(BINDIR)/$(OUTNAME).elf LDTIMEOBJ:=$(BINDIR)/_pros_ld_timestamp.o +MONOLITH_BIN:=$(BINDIR)/monolith.bin +MONOLITH_ELF:=$(basename $(MONOLITH_BIN)).elf + +HOT_BIN:=$(BINDIR)/hot.package.bin +HOT_ELF:=$(basename $(HOT_BIN)).elf +COLD_BIN:=$(BINDIR)/cold.package.bin +COLD_ELF:=$(basename $(COLD_BIN)).elf + +# Check if USE_PACKAGE is defined to check for migration steps from purduesigbots/pros#87 +ifndef USE_PACKAGE +$(error Your Makefile must be migrated! Visit https://pros.cs.purdue.edu/v5/releases/kernel3.1.6.html to learn how) +endif + +DEFAULT_BIN=$(MONOLITH_BIN) +ifeq ($(USE_PACKAGE),1) +DEFAULT_BIN=$(HOT_BIN) +endif + .PHONY: all clean quick -quick: $(OUTBIN) +quick: $(DEFAULT_BIN) -all: clean $(OUTBIN) +all: clean $(DEFAULT_BIN) clean: @echo Cleaning project @@ -148,6 +161,7 @@ clean-template: -$Drm -rf $(TEMPLATE_DIR) $(LIBAR): $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)) $(EXTRA_LIB_DEPS) + -$Drm -f $@ @echo -n "Creating $@ " $(call test_output,$D$(AR) rcs $@ $^, $(DONE_STRING)) @@ -161,20 +175,44 @@ endif # if project is a library source, compile the archive and link output.elf against the archive rather than source objects ifeq ($(IS_LIBRARY),1) -OUTELF_DEPS=$(filter-out $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)), $(call GETALLOBJ,$(EXCLUDE_SRCDIRS))) +ELF_DEPS=$(filter-out $(call GETALLOBJ,$(EXCLUDE_SRC_FROM_LIB)), $(call GETALLOBJ,$(EXCLUDE_SRCDIRS))) LIBRARIES+=$(LIBAR) else -OUTELF_DEPS=$(call GETALLOBJ,$(EXCLUDE_SRCDIRS)) +ELF_DEPS=$(call GETALLOBJ,$(EXCLUDE_SRCDIRS)) endif -$(OUTBIN): $(OUTELF) $(BINDIR) +$(MONOLITH_BIN): $(MONOLITH_ELF) $(BINDIR) @echo -n "Creating $@ for $(DEVICE) " - $(call test_output,$D$(OBJCOPY) $< -O binary $@,$(DONE_STRING)) + $(call test_output,$D$(OBJCOPY) $< -O binary -R .hot_init $@,$(DONE_STRING)) -$(OUTELF): $(OUTELF_DEPS) $(LIBRARIES) +$(MONOLITH_ELF): $(ELF_DEPS) $(LIBRARIES) $(call _pros_ld_timestamp) @echo -n "Linking project with $(ARCHIVE_TEXT_LIST) " - $(call test_output,$D$(LD) $(LDFLAGS) $(OUTELF_DEPS) $(LDTIMEOBJ) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS)) -o $@,$(OK_STRING)) + $(call test_output,$D$(LD) $(LDFLAGS) $(ELF_DEPS) $(LDTIMEOBJ) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS)) -o $@,$(OK_STRING)) + @echo Section sizes: + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +$(COLD_BIN): $(COLD_ELF) + @echo -n "Creating cold package binary for $(DEVICE) " + $(call test_output,$D$(OBJCOPY) $< -O binary -R .hot_init $@,$(DONE_STRING)) + +$(COLD_ELF): $(LIBRARIES) + $(call _pros_ld_timestamp) + @echo -n "Creating cold package with $(ARCHIVE_TEXT_LIST) " + $(call test_output,$D$(LD) $(LDFLAGS) $(LDTIMEOBJ) $(call wlprefix,--gc-keep-exported --whole-archive $^ -lstdc++ --no-whole-archive) $(call wlprefix,-T$(FWDIR)/v5.ld $(LNK_FLAGS) -o $@),$(OK_STRING)) + @echo -n "Stripping cold package " + $(call test_output,$D$(OBJCOPY) --strip-symbol=install_hot_table --strip-symbol=__libc_init_array --strip-symbol=_PROS_COMPILE_DIRECTORY --strip-symbol=_PROS_COMPILE_TIMESTAMP $@ $@, $(DONE_STRING)) + @echo Section sizes: + -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) + +$(HOT_BIN): $(HOT_ELF) $(COLD_BIN) + @echo -n "Creating $@ for $(DEVICE) " + $(call test_output,$D$(OBJCOPY) $< -O binary $@,$(DONE_STRING)) + +$(HOT_ELF): $(COLD_ELF) $(ELF_DEPS) + $(call _pros_ld_timestamp) + @echo -n "Linking hot project with $(COLD_ELF) and $(ARCHIVE_TEXT_LIST) " + $(call test_output,$D$(LD) $(LDFLAGS) $(call wlprefix,-nostartfiles -R $<) $(filter-out $<,$^) $(LDTIMEOBJ) $(LIBRARIES) $(call wlprefix,-T$(FWDIR)/v5-hot.ld $(LNK_FLAGS) -o $@),$(OK_STRING)) @echo Section sizes: -$(VV)$(SIZETOOL) $(SIZEFLAGS) $@ $(SIZES_SED) $(SIZES_NUMFMT) @@ -203,11 +241,12 @@ endef $(foreach cxxext,$(CXXEXTS),$(eval $(call cxx_rule,$(cxxext)))) define _pros_ld_timestamp +$(VV)mkdir -p $(dir $(LDTIMEOBJ)) @echo -n "Adding timestamp " @# Pipe a line of code defining _PROS_COMPILE_TOOLSTAMP and _PROS_COMPILE_DIRECTORY into GCC, @# which allows compilation from stdin. We define _PROS_COMPILE_DIRECTORY using a command line-defined macro @# which is the pwd | tail bit, which will truncate the path to the last 23 characters -$(call test_output, $(VV)echo 'char const * const _PROS_COMPILE_TIMESTAMP = __DATE__ " " __TIME__; char const * const _PROS_COMPILE_DIRECTORY = PCD;' | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) -DPCD="\"`pwd | tail -c 23`\"" -o $(LDTIMEOBJ) -,$(OK_STRING)) +$(call test_output, $(VV)echo 'char const * const _PROS_COMPILE_TIMESTAMP = __DATE__ " " __TIME__; char const * const _PROS_COMPILE_DIRECTORY = "$(shell pwd | tail -c 23)";' | $(CC) -c -x c $(CFLAGS) $(EXTRA_CFLAGS) -o $(LDTIMEOBJ) -,$(OK_STRING)) endef # these rules are for build-compile-commands, which just print out sysroot information diff --git a/firmware/v5-common.ld b/firmware/v5-common.ld new file mode 100644 index 000000000..dafa8d823 --- /dev/null +++ b/firmware/v5-common.ld @@ -0,0 +1,9 @@ +_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x02E00000; /* ~48 MB */ + +MEMORY +{ + /* user code 72M */ + COLD_MEMORY : ORIGIN = 0x03800000, LENGTH = 0x04800000 /* Just under 19 MB */ + HEAP : ORIGIN = 0x04A00000, LENGTH = _HEAP_SIZE + HOT_MEMORY : ORIGIN = 0x07800000, LENGTH = 0x00800000 /* Just over 8 MB */ +} diff --git a/firmware/v5-hot.ld b/firmware/v5-hot.ld new file mode 100644 index 000000000..75594efcc --- /dev/null +++ b/firmware/v5-hot.ld @@ -0,0 +1,236 @@ +/*******************************************************************/ +/* */ +/* This file is nearly the same as v5.ld, except that everything */ +/* goes in HOT_MEMORY and HOT user code doesn't need heap or stack */ +/* (only the cold memory code - PROS does) */ +/* */ +/*******************************************************************/ + +/* Define Memories in the system */ +INCLUDE firmware/v5-common.ld + +/* Make install_hot_table entry point so that linker can prune from there */ +ENTRY(install_hot_table) + +/* Define the sections, and where they are mapped in memory */ +SECTIONS +{ +/* Since install_hot_table is the entry point, it should be the first address + * in memory, but this makes sure it happens explicitly and consistently with + * cold linkage */ +.hot_init : { + KEEP (*(.hot_magic)) + KEEP (*(.hot_init)) +} > HOT_MEMORY +.text : { + KEEP (*(.vectors)) + /* boot data should be exactly 32 bytes long */ + *(.boot_data) + . = 0x20; + *(.boot) + . = ALIGN(64); + *(.freertos_vectors) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + *(.plt) + *(.gnu_warning) + *(.gcc_execpt_table) + *(.glue_7) + *(.glue_7t) + *(.vfp11_veneer) + *(.ARM.extab) + *(.gnu.linkonce.armextab.*) +} > HOT_MEMORY + +.init : { + KEEP (*(.init)) +} > HOT_MEMORY + +.fini : { + KEEP (*(.fini)) +} > HOT_MEMORY + +.rodata : { + __rodata_start = .; + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + __rodata_end = .; +} > HOT_MEMORY + +.rodata1 : { + __rodata1_start = .; + *(.rodata1) + *(.rodata1.*) + __rodata1_end = .; +} > HOT_MEMORY + +.sdata2 : { + __sdata2_start = .; + *(.sdata2) + *(.sdata2.*) + *(.gnu.linkonce.s2.*) + __sdata2_end = .; +} > HOT_MEMORY + +.sbss2 : { + __sbss2_start = .; + *(.sbss2) + *(.sbss2.*) + *(.gnu.linkonce.sb2.*) + __sbss2_end = .; +} > HOT_MEMORY + +.data : { + __data_start = .; + *(.data) + *(.data.*) + *(.gnu.linkonce.d.*) + *(.jcr) + *(.got) + *(.got.plt) + __data_end = .; +} > HOT_MEMORY + +.data1 : { + __data1_start = .; + *(.data1) + *(.data1.*) + __data1_end = .; +} > HOT_MEMORY + +.got : { + *(.got) +} > HOT_MEMORY + +.ctors : { + __CTOR_LIST__ = .; + ___CTORS_LIST___ = .; + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + __CTOR_END__ = .; + ___CTORS_END___ = .; +} > HOT_MEMORY + +.dtors : { + __DTOR_LIST__ = .; + ___DTORS_LIST___ = .; + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE(*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + __DTOR_END__ = .; + ___DTORS_END___ = .; +} > HOT_MEMORY + +.fixup : { + __fixup_start = .; + *(.fixup) + __fixup_end = .; +} > HOT_MEMORY + +.eh_frame : { + *(.eh_frame) +} > HOT_MEMORY + +.eh_framehdr : { + __eh_framehdr_start = .; + *(.eh_framehdr) + __eh_framehdr_end = .; +} > HOT_MEMORY + +.gcc_except_table : { + *(.gcc_except_table) +} > HOT_MEMORY + +.mmu_tbl (ALIGN(16384)) : { + __mmu_tbl_start = .; + *(.mmu_tbl) + __mmu_tbl_end = .; +} > HOT_MEMORY + +.ARM.exidx : { + __exidx_start = .; + *(.ARM.exidx*) + *(.gnu.linkonce.armexidix.*.*) + __exidx_end = .; +} > HOT_MEMORY + +.preinit_array : { + __preinit_array_start = .; + KEEP (*(SORT(.preinit_array.*))) + KEEP (*(.preinit_array)) + __preinit_array_end = .; +} > HOT_MEMORY + +.init_array : { + __init_array_start = .; + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __init_array_end = .; +} > HOT_MEMORY + +.fini_array : { + __fini_array_start = .; + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array)) + __fini_array_end = .; +} > HOT_MEMORY + +.ARM.attributes : { + __ARM.attributes_start = .; + *(.ARM.attributes) + __ARM.attributes_end = .; +} > HOT_MEMORY + +.sdata : { + __sdata_start = .; + *(.sdata) + *(.sdata.*) + *(.gnu.linkonce.s.*) + __sdata_end = .; +} > HOT_MEMORY + +.sbss (NOLOAD) : { + __sbss_start = .; + *(.sbss) + *(.sbss.*) + *(.gnu.linkonce.sb.*) + __sbss_end = .; +} > HOT_MEMORY + +.tdata : { + __tdata_start = .; + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + __tdata_end = .; +} > HOT_MEMORY + +.tbss : { + __tbss_start = .; + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + __tbss_end = .; +} > HOT_MEMORY + +.bss (NOLOAD) : { + __bss_start = .; + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b.*) + *(COMMON) + __bss_end = .; +} > HOT_MEMORY + +_SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 ); + +_SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); + +/* HOT memory doesn't need a stack or heap */ +_end = .; +} diff --git a/firmware/v5.ld b/firmware/v5.ld index d14d3f857..d82db22d9 100644 --- a/firmware/v5.ld +++ b/firmware/v5.ld @@ -11,10 +11,10 @@ /* */ /*******************************************************************/ -/* Stack is used in 3rd party user code */ +/* This stack is used during initialization, but FreeRTOS tasks have their own + stack allocated in BSS or Heap (kernel tasks in FreeRTOS .bss heap; user tasks + in standard heap) */ _STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000; -/* Allocate 1MB of memory to the heap for now */ -_HEAP_SIZE = DEFINED(_HEAP_SIZE) ? _HEAP_SIZE : 0x100000; _ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024; _SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048; @@ -24,11 +24,7 @@ _UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024; /* Define Memories in the system */ -MEMORY -{ - /* user code 72M */ - ps7_ddr_0_S_AXI_BASEADDR : ORIGIN = 0x03800000, LENGTH = 0x04800000 -} +INCLUDE firmware/v5-common.ld /* Specify the default entry point to the program */ @@ -38,6 +34,13 @@ ENTRY(vexStartup) SECTIONS { +/* THis will get stripped out before uploading, but we need to place code + here so we can at least link to it (install_hot_table) */ +.hot_init : { + KEEP (*(.hot_magic)) + KEEP (*(.hot_init)) +} > HOT_MEMORY + .text : { KEEP (*(.vectors)) /* boot data should be exactly 32 bytes long */ @@ -57,15 +60,15 @@ SECTIONS *(.vfp11_veneer) *(.ARM.extab) *(.gnu.linkonce.armextab.*) -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .init : { KEEP (*(.init)) -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .fini : { KEEP (*(.fini)) -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .rodata : { __rodata_start = .; @@ -73,14 +76,14 @@ SECTIONS *(.rodata.*) *(.gnu.linkonce.r.*) __rodata_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .rodata1 : { __rodata1_start = .; *(.rodata1) *(.rodata1.*) __rodata1_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .sdata2 : { __sdata2_start = .; @@ -88,7 +91,7 @@ SECTIONS *(.sdata2.*) *(.gnu.linkonce.s2.*) __sdata2_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .sbss2 : { __sbss2_start = .; @@ -96,7 +99,7 @@ SECTIONS *(.sbss2.*) *(.gnu.linkonce.sb2.*) __sbss2_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .data : { __data_start = .; @@ -107,18 +110,18 @@ SECTIONS *(.got) *(.got.plt) __data_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .data1 : { __data1_start = .; *(.data1) *(.data1.*) __data1_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .got : { *(.got) -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .ctors : { __CTOR_LIST__ = .; @@ -129,7 +132,7 @@ SECTIONS KEEP (*(.ctors)) __CTOR_END__ = .; ___CTORS_END___ = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .dtors : { __DTOR_LIST__ = .; @@ -140,67 +143,67 @@ SECTIONS KEEP (*(.dtors)) __DTOR_END__ = .; ___DTORS_END___ = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .fixup : { __fixup_start = .; *(.fixup) __fixup_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .eh_frame : { *(.eh_frame) -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .eh_framehdr : { __eh_framehdr_start = .; *(.eh_framehdr) __eh_framehdr_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .gcc_except_table : { *(.gcc_except_table) -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .mmu_tbl (ALIGN(16384)) : { __mmu_tbl_start = .; *(.mmu_tbl) __mmu_tbl_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .ARM.exidx : { __exidx_start = .; *(.ARM.exidx*) *(.gnu.linkonce.armexidix.*.*) __exidx_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .preinit_array : { __preinit_array_start = .; KEEP (*(SORT(.preinit_array.*))) KEEP (*(.preinit_array)) __preinit_array_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .init_array : { __init_array_start = .; KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) __init_array_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .fini_array : { __fini_array_start = .; KEEP (*(SORT(.fini_array.*))) KEEP (*(.fini_array)) __fini_array_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .ARM.attributes : { __ARM.attributes_start = .; *(.ARM.attributes) __ARM.attributes_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .sdata : { __sdata_start = .; @@ -208,7 +211,7 @@ SECTIONS *(.sdata.*) *(.gnu.linkonce.s.*) __sdata_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .sbss (NOLOAD) : { __sbss_start = .; @@ -216,7 +219,7 @@ SECTIONS *(.sbss.*) *(.gnu.linkonce.sb.*) __sbss_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .tdata : { __tdata_start = .; @@ -224,7 +227,7 @@ SECTIONS *(.tdata.*) *(.gnu.linkonce.td.*) __tdata_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .tbss : { __tbss_start = .; @@ -232,7 +235,7 @@ SECTIONS *(.tbss.*) *(.gnu.linkonce.tb.*) __tbss_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY .bss (NOLOAD) : { __bss_start = .; @@ -241,7 +244,7 @@ SECTIONS *(.gnu.linkonce.b.*) *(COMMON) __bss_end = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY _SDA_BASE_ = __sdata_start + ((__sbss_end - __sdata_start) / 2 ); @@ -257,7 +260,7 @@ _SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); . += _HEAP_SIZE; _heap_end = .; HeapLimit = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > HEAP .stack (NOLOAD) : { . = ALIGN(16); @@ -287,7 +290,7 @@ _SDA2_BASE_ = __sdata2_start + ((__sbss2_end - __sdata2_start) / 2 ); . += _UNDEF_STACK_SIZE; . = ALIGN(16); __undef_stack = .; -} > ps7_ddr_0_S_AXI_BASEADDR +} > COLD_MEMORY _end = .; } diff --git a/include/system/hot.h b/include/system/hot.h new file mode 100644 index 000000000..ea6c99eaf --- /dev/null +++ b/include/system/hot.h @@ -0,0 +1,14 @@ +#pragma once + +struct hot_table { + char const* compile_timestamp; + char const* compile_directory; + + struct { +#define FUNC(F) void (*F)(); +#include "system/user_functions/list.h" +#undef FUNC + } functions; +}; + +extern struct hot_table* const HOT_TABLE; diff --git a/include/system/user_functions.h b/include/system/user_functions.h new file mode 100644 index 000000000..c9e60ca00 --- /dev/null +++ b/include/system/user_functions.h @@ -0,0 +1,5 @@ +#pragma once + +#define FUNC(F) void user_ ##F(); +#include "system/user_functions/list.h" +#undef FUNC diff --git a/include/system/user_functions/c_list.h b/include/system/user_functions/c_list.h new file mode 100644 index 000000000..9cb5cfd72 --- /dev/null +++ b/include/system/user_functions/c_list.h @@ -0,0 +1,9 @@ +#ifndef FUNC +#error "FUNC must be defined" +#endif + +FUNC(autonomous) +FUNC(initialize) +FUNC(opcontrol) +FUNC(disabled) +FUNC(competition_initialize) diff --git a/include/system/user_functions/cpp_list.h b/include/system/user_functions/cpp_list.h new file mode 100644 index 000000000..d087b92fd --- /dev/null +++ b/include/system/user_functions/cpp_list.h @@ -0,0 +1,9 @@ +#ifndef FUNC +#error "FUNC must be defined" +#endif + +FUNC(cpp_autonomous) +FUNC(cpp_initialize) +FUNC(cpp_opcontrol) +FUNC(cpp_disabled) +FUNC(cpp_competition_initialize) diff --git a/include/system/user_functions/list.h b/include/system/user_functions/list.h new file mode 100644 index 000000000..494315b2a --- /dev/null +++ b/include/system/user_functions/list.h @@ -0,0 +1,6 @@ +#ifndef FUNC +#error "FUNC must be defined" +#endif + +#include "system/user_functions/c_list.h" +#include "system/user_functions/cpp_list.h" diff --git a/project.pros b/project.pros index 08aa99332..5cabc7ebe 100644 --- a/project.pros +++ b/project.pros @@ -1 +1 @@ -{"py/object": "pros.conductor.project.Project", "py/state": {"project_name": "hello", "target": "v5", "templates": {"kernel": {"py/object": "pros.conductor.templates.local_template.LocalTemplate", "location": "C:\\Users\\Elliot\\AppData\\Roaming\\PROS\\templates\\kernel@3.0.0-beta1", "metadata": {"origin": "local", "output": "bin/output.bin"}, "name": "kernel", "supported_kernels": null, "system_files": ["include\\pros\\api_legacy.h", "include\\pros\\misc.h", "include\\pros\\colors.h", "include\\api.h", "include\\pros\\motors.h", "firmware\\libpros.a", "include\\pros\\tmei.h", "include\\pros\\apix.h", "common.mk", "include\\pros\\adi.h", "include\\pros\\rtos.h", "Makefile", "firmware\\v5.ld", "include\\pros\\llemu.h"], "target": "v5", "user_files": ["src\\autonomous.c", "src\\autonomous.cpp", "src\\initialize.c", "src\\opcontrol.cpp", "src\\initialize.cpp", "src\\opcontrol.c"], "version": "3.0.0-beta1"}}, "upload_options": {}}} +{"py/object": "pros.conductor.project.Project", "py/state": {"project_name": "kernel-dev", "target": "v5", "templates": {"kernel": {"py/object": "pros.conductor.templates.local_template.LocalTemplate", "location": "./template", "metadata": {"origin": "local", "output": "bin/monolith.bin", "hot_output": "bin/hot.package.bin", "cold_output": "bin/cold.package.bin", "cold_addr": 58720256, "hot_addr": 125829120}, "name": "kernel", "supported_kernels": null, "system_files": [], "target": "v5", "user_files": [], "version": "3.0.0-beta1"}}, "upload_options": {}}} diff --git a/src/system/cpp_support.cpp b/src/system/cpp_support.cpp index 873d8b278..8c0bc6149 100644 --- a/src/system/cpp_support.cpp +++ b/src/system/cpp_support.cpp @@ -19,22 +19,6 @@ #include "rtos/task.h" #include "v5_api.h" -void* operator new(size_t size) { - return malloc(size); -} - -void* operator new[](size_t size) { - return malloc(size); -} - -void operator delete(void* p) { - free(p); -} - -void operator delete[](void* p) { - free(p); -} - extern "C" void task_fn_wrapper(task_fn_t fn, void* args) { #ifdef __cpp_exceptions try { diff --git a/src/system/dev/ser_daemon.c b/src/system/dev/ser_daemon.c index c8352f2da..27245a5c6 100644 --- a/src/system/dev/ser_daemon.c +++ b/src/system/dev/ser_daemon.c @@ -19,6 +19,7 @@ #include "kapi.h" #include "system/dev/banners.h" +#include "system/hot.h" #include "system/optimizers.h" #include "v5_api.h" @@ -29,8 +30,10 @@ __attribute__((weak)) char const* const _PROS_COMPILE_DIRECTORY = "Unknown"; void print_small_banner(void) { uint32_t uptime = millis(); - iprintf(short_banner, PROS_VERSION_STRING, uptime / 1000, uptime % 1000, _PROS_COMPILE_TIMESTAMP, - _PROS_COMPILE_DIRECTORY); + char const * const timestamp = (HOT_TABLE && HOT_TABLE->compile_timestamp) ? HOT_TABLE->compile_timestamp : _PROS_COMPILE_TIMESTAMP; + char const * const directory = (HOT_TABLE && HOT_TABLE->compile_directory) ? HOT_TABLE->compile_directory : _PROS_COMPILE_DIRECTORY; + iprintf(short_banner, PROS_VERSION_STRING, uptime / 1000, uptime % 1000, timestamp, + directory); } void print_large_banner(void) { @@ -38,8 +41,10 @@ void print_large_banner(void) { uint32_t* sys_ver = (uint32_t*)version; *sys_ver = vexSystemVersion(); uint32_t uptime = millis(); + char const * const timestamp = (HOT_TABLE && HOT_TABLE->compile_timestamp) ? HOT_TABLE->compile_timestamp : _PROS_COMPILE_TIMESTAMP; + char const * const directory = (HOT_TABLE && HOT_TABLE->compile_directory) ? HOT_TABLE->compile_directory : _PROS_COMPILE_DIRECTORY; iprintf(large_banner, PROS_VERSION_STRING, version[3], version[2], version[1], version[0], uptime / 1000, - uptime % 1000, _PROS_COMPILE_TIMESTAMP, _PROS_COMPILE_DIRECTORY); + uptime % 1000, timestamp, directory); } /******************************************************************************/ diff --git a/src/system/hot.c b/src/system/hot.c new file mode 100644 index 000000000..c1d06cdeb --- /dev/null +++ b/src/system/hot.c @@ -0,0 +1,77 @@ +#include "kapi.h" +#include "system/hot.h" +#include "v5_api.h" + + +// stored only in cold +struct hot_table __HOT_TABLE = { 0 }; +struct hot_table* const HOT_TABLE = &__HOT_TABLE; + +#define MAGIC0 0x52616368 +#define MAGIC1 0x8CEF7310 + +__attribute__((section (".hot_magic"))) uint32_t MAGIC[] = {MAGIC0, MAGIC1}; +uint32_t const volatile * const MAGIC_ADDR = MAGIC; + +// The linker decides on these symbols in each section just as normal +// When linking in hot, these pointers work just like any other weak symbol +// Note: to get C++ style initialize and friends, we strip out cpp_initialize and friends so that linker +// regenerates that function with the call to the correct (user-written) C++ version +extern char const* _PROS_COMPILE_TIMESTAMP; +extern char const* _PROS_COMPILE_DIRECTORY; + +// this expands to a bunch of: +// extern void autonomous(); +#define FUNC(F) void F(); +#include "system/user_functions/list.h" +#undef FUNC + +__attribute__((section (".hot_init"))) +void install_hot_table(struct hot_table* const tbl) { + // printf("Hot initializing\n"); + tbl->compile_timestamp = _PROS_COMPILE_TIMESTAMP; + tbl->compile_directory = _PROS_COMPILE_DIRECTORY; + + // this expands to a bunch of: + // tbl->functions.autonomous = autonomous; + #define FUNC(F) tbl->functions.F = F; + #include "system/user_functions/list.h" + #undef FUNC + + // all of these weak symbols are given to us by the linker + // These values should come from the hot region, since that's where this + // function is linked + extern __attribute__((weak)) uint8_t* __sbss_start[]; + extern __attribute__((weak)) uint8_t* __sbss_end[]; + memset(__sbss_start, 0, (size_t)__sbss_end - (size_t)__sbss_start); + + extern __attribute__((weak)) uint8_t* __bss_start[]; + extern __attribute__((weak)) uint8_t* __bss_end[]; + memset(__bss_start, 0, (size_t)__bss_end - (size_t)__bss_start); + + extern __attribute__((weak)) void (* const __preinit_array_start[])(void); + extern __attribute__((weak)) void (* const __preinit_array_end[])(void); + for(void (* const *ctor)() = __preinit_array_start; ctor < __preinit_array_end; ctor++) { + (*ctor)(); + } + + extern __attribute__((weak)) void (* const __init_array_start[])(void); + extern __attribute__((weak)) void (* const __init_array_end[])(void); + for(void (* const *ctor)() = __init_array_start; ctor < __init_array_end; ctor++) { + (*ctor)(); + } +} + +// this function really exists on the cold section! Called by pros_init +// this does the check if we're running with hot/cold and invokes the hot table +// installer (install_hot_table) located in hot memory +void invoke_install_hot_table() { + // install_hot_table is at 0x07800008 + // MAGIC_ADDR is at 0x0780000 + // printf("%s %p %p %x %x\n", __FUNCTION__, (void*)install_hot_table, (void*)HOT_TABLE, MAGIC_ADDR[0], MAGIC_ADDR[1]); + if(vexSystemLinkAddrGet() == (uint32_t)0x03800000 && MAGIC_ADDR[0] == MAGIC0 && MAGIC_ADDR[1] == MAGIC1) { + install_hot_table(HOT_TABLE); + } else { + memset(HOT_TABLE, 0, sizeof(*HOT_TABLE)); + } +} diff --git a/src/system/main.c b/src/system/main.c index 7a12b4788..fae0641c8 100644 --- a/src/system/main.c +++ b/src/system/main.c @@ -25,6 +25,7 @@ extern void system_daemon_initialize(); extern void display_initialize(void); extern void rtos_sched_start(); extern void vdml_initialize(); +extern void invoke_install_hot_table(); // XXX: pros_init happens inside __libc_init_array, and before any global // C++ constructors are invoked. This is accomplished by instructing @@ -42,6 +43,8 @@ __attribute__((constructor(101))) static void pros_init(void) { system_daemon_initialize(); display_initialize(); + + invoke_install_hot_table(); } int main() { diff --git a/src/system/system_daemon.c b/src/system/system_daemon.c index 14cf57130..65626787a 100644 --- a/src/system/system_daemon.c +++ b/src/system/system_daemon.c @@ -13,6 +13,7 @@ #include "kapi.h" #include "system/optimizers.h" +#include "system/user_functions.h" #include "v5_api.h" extern void vdml_background_processing(); @@ -126,54 +127,8 @@ void system_daemon_initialize() { "PROS System Daemon", system_daemon_task_stack, &system_daemon_task_buffer); } -// description of some cases for implementing autonomous: -// user implements autonomous w/C linkage: system daemon starts _autonomous_task -// which calls the user's autonomous() implement w/C++ linkage: sysd starts -// _autonomous_task calls autonomous() defined here which calls cpp_autonomous -// which calls the user's C++ linkage autonomous() implement no autonomous: see -// above, but cpp_autonomous implements a stub C++ autonomous() - -// Our weak functions call C++ links of these functions, allowing users to only optionally extern "C" the task functions -extern void cpp_autonomous(); -extern void cpp_initialize(); -extern void cpp_opcontrol(); -extern void cpp_disabled(); -extern void cpp_competition_initialize(); - -// default implementations of the different competition modes attempt to call -// the C++ linkage version of the function -__attribute__((weak)) void autonomous() { - cpp_autonomous(); -} -__attribute__((weak)) void initialize() { - cpp_initialize(); -} -__attribute__((weak)) void opcontrol() { - cpp_opcontrol(); -} -__attribute__((weak)) void disabled() { - cpp_disabled(); -} -__attribute__((weak)) void competition_initialize() { - cpp_competition_initialize(); -} - // these functions are what actually get called by the system daemon, which // attempt to call whatever the user declares -static void _competition_initialize_task(void* ign) { - competition_initialize(); -} - -static void _initialize_task(void* ign) { - initialize(); - task_notify(system_daemon_task); -} -static void _autonomous_task(void* ign) { - autonomous(); -} -static void _opcontrol_task(void* ign) { - opcontrol(); -} -static void _disabled_task(void* ign) { - disabled(); -} +#define FUNC(NAME) static void _##NAME##_task(void* ign) { user_##NAME(); task_notify(system_daemon_task); } +#include "system/user_functions/c_list.h" +#undef FUNC diff --git a/src/system/user_functions.c b/src/system/user_functions.c new file mode 100644 index 000000000..f53c1b5bc --- /dev/null +++ b/src/system/user_functions.c @@ -0,0 +1,44 @@ +#include "kapi.h" +#include "system/hot.h" +#include "system/user_functions.h" + +// how this all works... +// system daemon starts an autonomous task which calls user_autonomous() +// user_autonomous will invoke a hot-linked autonomous if one is available +// The invoked autonomous may actually just invoke user_cpp_autonomous +// which will invoke a C routine which calls C++ autonomous routine + +// Our weak functions call C++ links of these functions, allowing users to only optionally extern "C" the task functions +// these are implemented in cpp_support.cpp +// FUNC(cpp_autonomous) expands to: +// extern void cpp_autonomous(); +#define FUNC(NAME) extern void NAME(); +#include "system/user_functions/cpp_list.h" +#undef FUNC + +// default implementations of the different competition modes attempt to call +// the C++ linkage version of the function +// FUNC(autonomous) exapnds to: +// __attribute__((weak)) void autonomous() { user_cpp_autonomous(); } +#define FUNC(NAME) __attribute__((weak)) void NAME() { user_cpp_##NAME(); } +#include "system/user_functions/c_list.h" +#undef FUNC + +// FUNC(cpp_autonomous) exapnds to: +// void user_cpp_autonomous() { +// if(HOT_TABLE && HOT_TABLE->functions.cpp_autonomous) { +// HOT_TABLE->functions.cpp_autonomous(); +// } else { +// cpp_autonomous(); +// } +// } +#define FUNC(NAME) \ + void user_##NAME() { \ + if (HOT_TABLE && HOT_TABLE->functions.NAME) { \ + HOT_TABLE->functions.NAME(); \ + } else { \ + NAME(); \ + } \ + } +#include "system/user_functions/list.h" +#undef FUNC diff --git a/template-Makefile b/template-Makefile index 9de3a3fef..9979c2912 100644 --- a/template-Makefile +++ b/template-Makefile @@ -16,6 +16,9 @@ WARNFLAGS+= EXTRA_CFLAGS= EXTRA_CXXFLAGS= +# Set to 1 to enable hot/cold linking +USE_PACKAGE:=0 + # Set this to 1 to add additional rules to compile your project as a PROS library template IS_LIBRARY:=0 # TODO: CHANGE THIS! From 47b06f08a7bd86b3158d1f7182d9249299809c89 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Sun, 17 Feb 2019 14:07:28 -0500 Subject: [PATCH 08/10] =?UTF-8?q?=F0=9F=A4=A6=E2=80=8D=E2=99=80=EF=B8=8F?= =?UTF-8?q?=20Dot=20between=20build=20ID=20and=20commit=20on=20Azure=20Pip?= =?UTF-8?q?elines=20(#113)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### Summary: Need a "." between build number and commit, not a plus #### Motivation: Use non-tagged templates built by Azure ##### References (optional): purduesigbots/pros-cli#66 purduesigbots/pros-cli#64 #### Test Plan: - [x] Can fetch/use template built locally - [x] Can fetch/use template built on Azure #### Commits: * dot between build number and commit * Dots are better in general --- version.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.py b/version.py index ade03af0e..e818f25ec 100644 --- a/version.py +++ b/version.py @@ -16,8 +16,8 @@ # pippre = 'alpha' if v.endswith('-dirty') else 'pre' build = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode().strip() number_since = subprocess.check_output(['git', 'rev-list', v[:v.index('-')] + '..HEAD', '--count']).decode().strip() - build = "{}+{}".format(number_since, build) - semver = bv + '-' + sempre + '+' + build + build = "{}.{}".format(number_since, build) + semver = bv + '-' + sempre + '.' + build else: semver = v From d3145c0fdf0187214f1bc16ac12d2fa0e291d1bb Mon Sep 17 00:00:00 2001 From: Jonathan Bayless Date: Sun, 17 Feb 2019 21:55:34 -0500 Subject: [PATCH 09/10] =?UTF-8?q?=F0=9F=90=9B=20Prevent=20Buffer=20Overrun?= =?UTF-8?q?=20in=20Controller=20Printing=20(#98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### Summary: This moves to more secure string operations for the `controller_set_text` and `controller_print` functions. Previously, `controller_print` would overrun the buffer when printing a string smaller than the maximum allowable length, and a string longer than CONTROLLER_MAX_COLS could be written into the smaller destination buffer in `controller_set_text`. #### Motivation: This will prevent buffer overrun and its associated issues in the controller printing functions. ##### References (optional): Closes #97. #### Test Plan: - [x] Compiles - [x] Call `controller_set_text` with a string longer than `CONTROLLER_MAX_COLS` - [x] Call `controller_print` with a string that is shorter than `CONTROLLER_MAX_COLS` #### Commits: * Improve controller printing safety * fix pointer reference * use strndup instead of strlcpy strlcpy is nonstandard, even by our standards (lol) --- src/devices/controller.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/devices/controller.c b/src/devices/controller.c index 084a56afd..aa2ccdd92 100644 --- a/src/devices/controller.c +++ b/src/devices/controller.c @@ -11,10 +11,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#define _GNU_SOURCE -// NOTE: this would normally be in the C file, but it won't compile that way -#include // vasprintf (GNU extension) -#undef _GNU_SOURCE +#include #include "kapi.h" #include "v5_api.h" @@ -207,9 +204,7 @@ int32_t controller_set_text(controller_id_e_t id, uint8_t line, uint8_t col, con else col++; - char* buf = (char*)malloc(CONTROLLER_MAX_COLS + 1); - strcpy(buf, str); - buf[CONTROLLER_MAX_COLS] = '\0'; + char* buf = strndup(str, CONTROLLER_MAX_COLS + 1); vexControllerTextSet(id, line, col, buf); free(buf); @@ -242,10 +237,8 @@ int32_t controller_print(controller_id_e_t id, uint8_t line, uint8_t col, const va_list args; va_start(args, fmt); - char* buf; - vasprintf(&buf, fmt, args); - - buf[CONTROLLER_MAX_COLS] = '\0'; + char* buf = (char*)malloc(CONTROLLER_MAX_COLS + 1); + vsnprintf(buf, CONTROLLER_MAX_COLS + 1, fmt, args); vexControllerTextSet(id, line, col, buf); free(buf); From 5a642a72cf314cbea35dad167addf8c121c75f68 Mon Sep 17 00:00:00 2001 From: Elliot Berman Date: Mon, 18 Feb 2019 13:17:45 -0500 Subject: [PATCH 10/10] Bump to 3.1.6 --- include/api.h | 4 ++-- version | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/api.h b/include/api.h index b9b0c58be..411cce42f 100644 --- a/include/api.h +++ b/include/api.h @@ -41,8 +41,8 @@ #define PROS_VERSION_MAJOR 3 #define PROS_VERSION_MINOR 1 -#define PROS_VERSION_PATCH 5 -#define PROS_VERSION_STRING "3.1.5" +#define PROS_VERSION_PATCH 6 +#define PROS_VERSION_STRING "3.1.6" #define PROS_ERR (INT32_MAX) #define PROS_ERR_F (INFINITY) diff --git a/version b/version index 0aec50e6e..9cec7165a 100644 --- a/version +++ b/version @@ -1 +1 @@ -3.1.4 +3.1.6