I’m working on reducing the size of the Monocypher package. There is one flag, that if it is not used, excludes two big files from the build.
But I cannot exclude these files via a srcFilter, since if this flag is set, the code does need those two files.
An extra compilation is that I cannot extend the library with a custom python file to resolve this issue via an custom build script. So what are the best options for handling this? Making a repo that takes a copy of the original release, and adds the PlatformIO specific code?
Most libraries I’m aware of always compile all the files but use
#ifdefs to remove the code. So if the flag is not set, the file is empty after the preprocessing stage, e.g.:
... code ...
Compilers don’t seem to have problems with source files that are effectively empty.
The same is applied to the header file .
True, not this library, the files here:
do no contain this kind of feature flag.
See here for the only mention of the flag (uses have to manually include the
I probably misunderstood the context and thought you were one of the authors. If so, you had full freedom to modify the library. But it seems you can’t change the original library.
The big file you are talking about: is it
sha512.c? If so, there is no need (and not potential) for optimization: It will always be compiled but only included in the final program if
ED5519_SHA512 is defined.
The reason is that the PlatformIO build system puts the object files of libraries into an archive (
.a file), and the linker will only pull the object files from the archive that are effectively used.
BTW: You might want to get familiar with the new project inspection feature of PlatformIO. It can analyze which functions and variables contribute how much to the overall code and RAM size.
okay, I was indeed mistaken about the .ar file, read a bit about it now.
It is unclear to me how the linker decides which objects in the .ar file to link, is it only based on exported symbols? (and the use of them in other code)
The linker starts with the object files that are provided directly (and not indirectly by an archive file). Then it identifies unsatisfied references, i.e. function calls and external variables whose target is not contained in the object files included so far. It then searches the libraries for these targets and adds the matching object files to the executable being built. This will satisfy some reference but possibly add additional unsatisfied references. The process is repeated until all references are satisfied (success) or the target of some unsatisfied references cannot be found (error).
Basically, the loader includes all object files that are directly or indirectly referenced from a few root files.
Another aspect you could investigate is the section granularity. The default is that the entire compilation unit becomes a single ELF section. So if a
.c file contains many functions, they will all be included if just a single one is used.
The standard C library works around this by putting each function into a separate
.c file. But there are also compiler options that could help and I don’t know if PlatformIO uses them (it’s likely platform specific). Have a look at the following options:
-ffunction-sections: Creates a separate ELF section for each function
-fdata-sections: Dito for data (global and static variables)
-Wl,--gc-sections: Instructs the linker to garbage collect unused ELF sections
These options are likely to increase the code size of the individual functions but might result in an overall smaller executable because fewer functions are included.