On 18/04/2021 00:47, Alexander Shpilkin via Gcc-help wrote: > Hi, > > On Fri, 2021-04-16 at 13:47 +0000, David Sherman wrote: >> We are using NXP's MCUXpresso to target ARM, and it uses gcc. We have >> a large project with several different configurations. The underlying >> library code gets compiled into libs and linked into the main >> application, and the main application has all the switches to enable or >> disable features. Despite using -Os, many chunks of code are still >> present, as are static variables, even though they never get used. We >> have tried turning on link time optimization, but it appears to have no >> effect. Some static variables are optimized away, but many remain. We >> have even tried making them part of their own section and using >> different linker directives that don't have that section specified, but >> they get linked in anyway. > > I don’t know anything about MCUXpresso specifically, but let me expand > a bit on David Brown’s general remarks. > > First of all, it’s not the job of -Os to remove unused code. Unless > the source explicitly checks for the __OPTIMIZE_SIZE__ macro (rare, but > not unheard of), the compiler will compile more or less the same code > at any optimization level. More optimization might enable it to > eliminate more code (e.g. if a C function declared 'static inline' ends > up inlined everywhere), but the dependency analysis is very > conservative and AFAIK setting -Os does not change anything about it. > I don’t actually know if GCC is capable of dropping unused static > variables at all, by the way. (This requires, for example, proving > that a pointer to the variable is never taken.) There is little difference (IME) about what is dropped or not between different variations on optimisation levels (-Os, -O2, -Og). But there is a huge difference between -O0 (no optimisation) and -O1. Once the compiler can do inter-procedural analysis, inlining and constant propagation, it can definitely start removing unused /static/ code and data. Static variables that are not used (or only written to), whose address is not taken or does not escape, are removed. Static functions that are called only once are inlined, those that are never called are never generated (unless you take pointers to them). Static libraries with each function in its own source file is certainly traditional for many uses, but it is not efficient in code space unless you expect that the solid majority of the code will not be needed in a given application. That applies to general-purpose libraries, but not to most embedded systems (like the OP has). In particular, having separate files for each function (or small group of functions) greatly reduces the scope for inter-procedural optimisations (unless you go all the way and use LTO), and severely limits the use of "static". For embedded systems, -fdata-sections -ffunction-sections -Wl,--gc-sections is standard practice. (Remember also to include "-fno-common" - it can sometimes have a surprisingly large effect on code size, and certainly on code speed, as well as being important to catch duplicate definition errors. And of course make everything static where possible.)