caab4045fa20627f1602955c53cacc05ea07de24 braney Fri Aug 14 11:01:17 2026 -0700 stop directory makefiles from overriding the tree compiler flags, refs #38094 hg/hgTracks/makefile has carried "COPT = -ggdb" since 2019-02-01. Every directory makefile includes inc/common.mk on its first line, so that assignment came after the tree default and replaced it. The result is that hgTracks itself has shipped with no optimization for seven years, while every library it links against was built with -O3. Building it with the tree default is 17.5% faster over a set of eight sessions, and 1.95x faster on a wide clinical view, with byte identical PNG output. Twenty three makefiles had a COPT or CFLAGS override. All are removed here. hg/visiGene/vgPrepImage keeps its defines, but appends them with += instead of assigning over the tree flags, because the ERMapper JPEG2000 headers need them. Compiling hg/hgTracks with optimization exposed seven errors that only appear under -O3. Four source files are fixed: hgTracks.c used an uninitialized labelfont, expRatioTracks.c and simpleTracks.c had five strncpy calls that could leave a string unterminated, and netTrack.c had two int buffers too small to hold the value written into them. The last two look like real latent bugs, not warning noise. checkCompileFlags.sh is added to stop this from recurring. The topChecks target runs it, so every build path reaches it. It fails the build on any COPT assignment, any CFLAGS assignment that is not +=, and any CFLAGS += carrying an -O flag. The check cannot live in inc/common.mk, because at the point common.mk is parsed the overriding line has not been read yet. A command line override such as "make COPT='-O0 -g'" still works, since the check reads only file contents. The 2026 conversion of the tree to -O3 did not find this. That work was driven by the warnings -O3 produces, and a directory that overrides COPT never receives the flag, so it never warns. Verified: the tree builds at -O3 with no new errors and no new warnings, and 80 rendered images compare pixel identical against the old build. diff --git src/hg/hgTracks/netTrack.c src/hg/hgTracks/netTrack.c index 64b0b923554..fd1cfa1c6a5 100644 --- src/hg/hgTracks/netTrack.c +++ src/hg/hgTracks/netTrack.c @@ -1,321 +1,321 @@ /* netTrack - stuff to handle loading and display of * netAlign type tracks in browser. Nets are derived * from cross-species alignments usually. */ /* Copyright (C) 2011 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include "hash.h" #include "linefile.h" #include "jksql.h" #include "hdb.h" #include "hgTracks.h" #include "netCart.h" #include "chainNetDbLoad.h" struct cartOptions { enum netColorEnum netColor; /* ChromColors, GrayScale */ enum netLevelEnum netLevel; /* filter chains by level 1 thru 6 (0==All) */ }; struct netItem /* A net track item. */ { struct netItem *next; int level; char *className; int yOffset; }; static char *netClassNames[] = { "Level 1", "Level 2", "Level 3", "Level 4", "Level 5", "Level 6", }; static struct netItem *makeNetItems() /* Make the levels for net alignment track. */ { struct netItem *ni, *niList = NULL; int i; int numClasses = ArraySize(netClassNames); for (i=0; ilevel = i; ni->className = netClassNames[i]; slAddHead(&niList, ni); } slReverse(&niList); return niList; } static void netLoad(struct track *tg) /* Load up net tracks. (Will query database during drawing for a change.) */ { tg->items = makeNetItems(); } static void netFree(struct track *tg) /* Free up netGroup items. */ { slFreeList(&tg->items); } static char *netName(struct track *tg, void *item) /* Return name of net level track. */ { struct netItem *ni = item; return ni->className; } static struct track *rTg; static struct hvGfx *rHvg; static int rX; /* X offset of drawing area. */ static int rHeightPer; /* Height of boxes. */ static int rMidLineOff; /* Offset to draw connecting lines. */ static int rNextLine; /* Y offset to next line. */ static double rScale; /* Scale from bases to pixels. */ static boolean rIsFull; /* Full display? */ static char *netColorLastChrom; static void netColorClearCache() { netColorLastChrom = "UNKNOWN"; } static Color netColor(struct track *tg, char *chrom, int level) /* return appropriate color for a chromosome/scaffold */ { struct cartOptions *netCart; netCart = (struct cartOptions *) tg->extraUiData; if (netCart->netColor == netColorGrayScale) switch(level) { case 1: return(shadesOfGray[9]); break; case 2: return(shadesOfGray[7]); break; case 3: return(shadesOfGray[6]); break; case 4: return(shadesOfGray[5]); break; case 5: return(shadesOfGray[4]); break; case 6: return(shadesOfGray[3]); break; default: return(shadesOfGray[2]); break; } static Color color; if (!sameString(chrom, netColorLastChrom)) color = getSeqColor(chrom, rHvg); if (0 == color) /* color 0 is actually an error condition, see */ color = MG_BLACK; /* makeChromosomeShades() in simpleTracks.c */ netColorLastChrom = chrom; return color; } static void rNetBox(struct hvGfx *hvg, struct cnFill *fill, int start, int end, int y, int level, Color color, Color barbColor, int orientation) /* Draw a scaled box. */ { int x1,x2,w; /* Do clipping before scaling because scaling may cause * integer overflow. */ if (start < winStart) start = winStart; if (end > winEnd) end = winEnd; if (start >= end) return; x1 = round((double)(start-winStart)*rScale) + rX; x2 = round((double)(end-winStart)*rScale) + rX; w = x2-x1; if (w < 1) w = 1; hvGfxBox(rHvg, x1, y, w, rHeightPer, color); if (w > 3) clippedBarbs(rHvg, x1, y+rMidLineOff, w, 2, 5, orientation, barbColor, TRUE); if (w > 1) { if (rNextLine > 0) /* Put up click info in full mode. */ { struct dyString *bubble = dyStringNew(256); - char depth[8]; + char depth[16]; snprintf(depth, sizeof(depth), "%d", level); dyStringPrintf(bubble, "%s %c %dk ", fill->qName, fill->qStrand, fill->qStart/1000); mapBoxHc(hvg, start, end, x1, y, w, rHeightPer, rTg->track, depth, bubble->string); dyStringFree(&bubble); } } } static void rNetLine(struct hvGfx *hvg, struct cnFill *gap, int y, int level, Color color, int orientation) /* Write out line filling gap and associated info. */ { int start = gap->tStart; int end = start + gap->tSize; int x1,x2,w; /* Do clipping before scaling because scaling may cause * integer overflow. */ if (start < winStart) start = winStart; if (end > winEnd) end = winEnd; if (start >= end) return; x1 = round((double)(start-winStart)*rScale) + rX; x2 = round((double)(end-winStart)*rScale) + rX; w = x2-x1; if (w >= 1) { struct dyString *bubble = dyStringNew(256); - char depth[8]; + char depth[16]; int midY = y + rMidLineOff; clippedBarbs(rHvg, x1, midY, w, 2, 5, orientation, color, FALSE); hvGfxLine(rHvg, x1, midY, x2, midY, color); if (rNextLine > 0) /* Put up click info in full mode. */ { snprintf(depth, sizeof(depth), "%d", level); dyStringPrintf(bubble, "size %d/%d Ns %d/%d newRep %d/%d", gap->qSize, gap->tSize, gap->qN, gap->tN, gap->qNewR, gap->tNewR); mapBoxHc(hvg, start, end, x1, y, w, rHeightPer, rTg->track, depth, bubble->string); dyStringFree(&bubble); } } } static void rNetDraw(struct track *tg, struct hvGfx *hvg, struct cnFill *fillList, int level, int y) /* Recursively draw net. */ { struct cnFill *fill; struct cnFill *gap; Color color, invColor; int orientation; for (fill = fillList; fill != NULL; fill = fill->next) { color = netColor(tg, fill->qName, level); invColor = hvGfxContrastingColor(rHvg, color); orientation = orientFromChar(fill->qStrand); if (fill->children == NULL || fill->tSize * rScale < 2.5) /* Draw single solid box if no gaps or no room to draw gaps. */ { rNetBox(hvg, fill, fill->tStart, fill->tStart + fill->tSize, y, level, color, invColor, orientation); } else { int fStart = fill->tStart; for ( gap = fill->children; gap != NULL; gap = gap->next) { if (gap->tSize * rScale >= 1) { rNetBox(hvg, fill, fStart, gap->tStart, y, level, color, invColor, orientation); fStart = gap->tStart + gap->tSize; rNetLine(hvg, gap, y, level+1, color, orientation); } } rNetBox(hvg, fill, fStart, fill->tStart + fill->tSize, y, level, color, invColor, orientation); } for (gap = fill->children; gap != NULL; gap = gap->next) { if (gap->children) { rNetDraw(tg, hvg, gap->children, level+2, y + rNextLine); } } } } static void netDraw(struct track *tg, int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font, Color color, enum trackVisibility vis) /* Draw routine for netAlign type tracks. This will load * the items as well as drawing them. */ { /* Load Net. */ struct chainNet *net = chainNetLoadRange(database, tg->table, chromName, seqStart, seqEnd, NULL); if (net != NULL) { /* Copy parameters to statics for recursive routine. */ rTg = tg; rHvg = hvg; rX = xOff; /* Clear cache. */ netColorClearCache(); /* Compute a few other positional things for recursive routine. */ rHeightPer = tg->heightPer; rMidLineOff = rHeightPer/2; rIsFull = (vis == tvFull || vis == tvPack || vis == tvSquish); if (rIsFull) rNextLine = tg->lineHeight; else rNextLine = 0; rScale = scaleForPixels(width); /* Recursively do main bit of work. */ rNetDraw(tg, hvg, net->fillList, 1, yOff); chainNetFree(&net); } } static int netTotalHeight(struct track *tg, enum trackVisibility vis) /* A copy of tgFixedTotalHeightNoOverflow() with visibility forced */ { int ret = 0; switch (vis) { case tvSquish: ret = tgFixedTotalHeightOptionalOverflow(tg, tvFull, (tl.fontHeight/3)+1, (tl.fontHeight/3), FALSE); break; case tvPack: ret = tgFixedTotalHeightOptionalOverflow(tg, tvFull, (tl.fontHeight/2)+1, (tl.fontHeight/2), FALSE); break; case tvFull: ret = tgFixedTotalHeightOptionalOverflow(tg, tvFull, tl.fontHeight+1, tl.fontHeight, FALSE); break; case tvDense: ret = tgFixedTotalHeightOptionalOverflow(tg, tvDense, tl.fontHeight+1, tl.fontHeight, FALSE); break; case tvHide: default: break; } return(ret); } void netMethods(struct track *tg) /* Make track group for chain/net alignment. */ { struct cartOptions *netCart; AllocVar(netCart); netCart->netColor = netFetchColorOption(cart, tg->tdb, FALSE); netCart->netLevel = netFetchLevelOption(cart, tg->tdb, FALSE); tg->loadItems = netLoad; tg->freeItems = netFree; tg->drawItems = netDraw; tg->itemName = netName; tg->mapItemName = netName; tg->totalHeight = netTotalHeight; tg->itemHeight = tgFixedItemHeight; tg->itemStart = tgItemNoStart; tg->itemEnd = tgItemNoEnd; tg->mapsSelf = TRUE; tg->extraUiData = (void *) netCart; }