Skip to content

Commit

Permalink
🔥 ⚠ Shuffle Makefiles (#87)
Browse files Browse the repository at this point in the history
#### 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)
  • Loading branch information
edjubuh authored Jan 31, 2019
1 parent f185362 commit bc0fa3e
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 210 deletions.
150 changes: 42 additions & 108 deletions Makefile
Original file line number Diff line number Diff line change
@@ -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)"
Expand All @@ -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))
114 changes: 111 additions & 3 deletions common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 -
Expand Down
Loading

0 comments on commit bc0fa3e

Please sign in to comment.