Browse Source

Fixed spurious CI failure caused by multiple writers to .o files

GCC is a bit frustrating here, it really wants to generate every file in
a single command, which _is_ more efficient if our build system could
leverage this. But -fcallgraph-info is a rather novel flag, so we can't
really rely on it for generally compiling and testing littlefs.

The multi-file output gets in the way when we want an explicitly
separate rule for callgraph-info generation. We can't generate the
callgraph-info without generating the objects files.

This becomes a surprsing issue when parallel building (make -j) is used!
Suddenly we might end up with both the .o and .ci rules writing to .o
files, which creates a really difficult to track down issue of corrupted
.o files.

The temporary solution is to use an order-only prerequisite. This still
ends up building the .o files twice, but it's an acceptable tradeoff for
not requiring the -fcallgraph-info for all builds.
Christopher Haster 3 years ago
parent
commit
3b495bab79
1 changed files with 15 additions and 21 deletions
  1. 15 21
      Makefile

+ 15 - 21
Makefile

@@ -124,16 +124,8 @@ coverage:
 	./scripts/coverage.py $(BUILDDIR)tests/*.toml.info -s $(COVERAGEFLAGS)
 
 .PHONY: summary
-summary: $(OBJ) $(CGI)
-	$(strip \
-		  ./scripts/code.py    $(OBJ) -q      -o - $(CODEFLAGS) \
-		| ./scripts/data.py    $(OBJ) -q -m - -o - $(DATAFLAGS) \
-		| ./scripts/stack.py   $(CGI) -q -m - -o - $(STACKFLAGS) \
-		| ./scripts/structs.py $(OBJ) -q -m - -o - $(STRUCTFLAGS) \
-		$(if $(COVERAGE),\
-			| ./scripts/coverage.py $(BUILDDIR)tests/*.toml.info \
-				-q -m - -o - $(COVERAGEFLAGS)) \
-		| ./scripts/summary.py -Y $(SUMMARYFLAGS))
+summary: $(BUILDDIR)lfs.csv
+	./scripts/summary.py -Y $^ $(SUMMARYFLAGS)
 
 
 # rules
@@ -147,15 +139,13 @@ $(BUILDDIR)lfs.a: $(OBJ)
 	$(AR) rcs $@ $^
 
 $(BUILDDIR)lfs.csv: $(OBJ) $(CGI)
-	$(strip \
-		  ./scripts/code.py    $(OBJ) -q      -o - $(CODEFLAGS) \
-		| ./scripts/data.py    $(OBJ) -q -m - -o - $(DATAFLAGS) \
-		| ./scripts/stack.py   $(CGI) -q -m - -o - $(STACKFLAGS) \
-		| ./scripts/structs.py $(OBJ) -q -m - -o - $(STRUCTFLAGS) \
-		$(if $(COVERAGE),\
-			| ./scripts/coverage.py $(BUILDDIR)tests/*.toml.info \
-				-q -m - -o - $(COVERAGEFLAGS)) \
-		> $@)
+	./scripts/code.py $(OBJ) -q $(CODEFLAGS) -o $@
+	./scripts/data.py $(OBJ) -q -m $@ $(DATAFLAGS) -o $@
+	./scripts/stack.py $(CGI) -q -m $@ $(STACKFLAGS) -o $@
+	./scripts/structs.py $(OBJ) -q -m $@ $(STRUCTSFLAGS) -o $@
+	$(if $(COVERAGE),\
+		./scripts/coverage.py $(BUILDDIR)tests/*.toml.info \
+			-q -m $@ $(COVERAGEFLAGS) -o $@)
 
 $(BUILDDIR)%.o: %.c
 	$(CC) -c -MMD $(CFLAGS) $< -o $@
@@ -163,8 +153,12 @@ $(BUILDDIR)%.o: %.c
 $(BUILDDIR)%.s: %.c
 	$(CC) -S $(CFLAGS) $< -o $@
 
-$(BUILDDIR)%.ci: %.c
-	$(CC) -c -MMD -fcallgraph-info=su $(CFLAGS) $< -o $(@:.ci=.o)
+# gcc depends on the output file for intermediate file names, so
+# we can't omit to .o output. We also need to serialize with the
+# normal .o rule because otherwise we can end up with multiprocess
+# problems with two instances of gcc modifying the same .o
+$(BUILDDIR)%.ci: %.c | $(BUILDDIR)%.o
+	$(CC) -c -MMD -fcallgraph-info=su $(CFLAGS) $< -o $|
 
 # clean everything
 .PHONY: clean