Precompiling a big library?

Generate archives

  1. Open the library.properties file from the root folder of your library in a text editor.
  2. Add this line to the file (reference):
    dot_a_linkage=true
    
  3. Save the file.
  4. In the Arduino IDE, select a target from the Tools > Board menu.
  5. Select File > Preferences from the Arduino IDE menus.
  6. Check the box next to Show verbose output during: ☐ compilation.
  7. Click the OK button.
  8. Compile any sketch that has an #include directive for your library.
    This could just be a bare minimum sketch. For example, if the library had a header SomeLibrary.h:
    #include <SomeLibrary.h>
    void setup() {}
    void loop() {}
    
  9. After the compilation finishes, examine the contents of the black console window of the Arduino IDE window.
    The first thing you need to find is the location of the temporary build folder. This should be shown in (among other places) the final command of the output.
    In my case, the command looks like this:
    "C:\\Users\\per\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino5/bin/   avr-size" -A "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_build_602003/PrecompiledTest.ino.elf"
    
    so I know the build folder is at this path:
    C:\Users\per\AppData\Local\Temp\arduino_build_602003
    
  10. The other thing you need to find in the output is the -mmcu flag passed to the compiler (may be -mcpu instead when compiling for other architectures).
    In my case it was in this command:
    "C:\\Users\\per\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino5/bin/avr-gcc" -Wall -Wextra -Os -g -flto -fuse-linker-plugin -Wl,--gc-sections,--relax -mmcu=atmega2560 -o "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_build_602003/PrecompiledTest.ino.elf" "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_build_602003\\sketch\\PrecompiledTest.ino.cpp.o" "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_build_602003\\libraries\\PrecompiledTest\\PrecompiledTest.a" "C:\\Users\\per\\AppData\\Local\\Temp\\arduino_build_602003/..\\arduino_cache_483105\\core\\core_arduino_avr_mega_cpu_atmega2560_99b4804b5450ac10a663b47fdad40a36.a" "-LC:\\Users\\per\\AppData\\Local\\Temp\\arduino_build_602003" -lm
    
    so you can see the flag was:
    -mmcu=atmega2560
    
    because I was compiling for the Mega 2560
  11. Copy the .a file from the <temporary build folder>/libraries/<library name> folder to appropriate subfolder of the library, as specified here (usually src/<target MCU>).
    In my case, the .a file was at this path:
    C:\Users\per\AppData\Local\Temp\arduino_build_602003\libraries\PrecompiledTest\PrecompiledTest.a
    
    and I copied it to the libraries/PrecompiledTest/src/atmega2560 folder.
  12. Rename the .a file by adding "lib" to the start (reference).
    In my case, it was renamed from PrecompiledTest.a to libPrecompiledTest.a
  13. Repeat the above process for all other targets you want to support.

Configure library metadata

  1. You can now remove the source files from the library, since they are replaced by the precompiled file.
    You also have the option of leaving the source files in place in order to allow compilation on demand for targets you haven't provided a pre-compiled binary for.
  2. Open library.properties in a text editor.
  3. Remove the line:
    dot_a_linkage=true
    
  4. Add the precompiled field to the library.properties file.
    Usually you will want to set this field to full:
    precompiled=full
    
    However, there is another "true" configuration option used for mixed pre-compiled libraries that contain precompiled components in addition to source code that should be compiled on demand.
    precompiled=true
    
    See the Arduino Library Specification for details.
  5. Save the file

ldflags field

You may also find the ldflags field of library.properties useful.

My understanding from reading this, and my test, is that defining ldflags is not needed in the case where you have used the expected filename for the .a file: lib<library name>.a, where <library name> is the value of the library's library.properties name field. In the case where you need to use a different file name, then you can specify this with the ldflags field. For example, if the library name was foo, but the archive file name was libbar.a, then you would need to add this line to library.properties:

ldflags=-lbar

note that you don't specify the "lib" or ".a" parts of the filename in the -l flag.

Boards platform configuration

Some Arduino boards platforms might also need adjustments to their platform.txt configuration file in order to support precompiled libraries, as documented here.

I discovered that in my simple proof of concept test library (which does use Arduino.h), I was able to use the stock "Arduino AVR Boards" platform version 1.8.2 without any modifications.

But this issue report indicates that might not always be so? I think it is only needed if you use the ldflags field in library.properties. In that case, you need to make sure platform.txt contains two things:

  • recipe.c.combine.pattern must contain the {compiler.libraries.ldflags} reference and it must be in the right position in the recipe, as shown here.
  • This line, anywhere in platform.txt:
    compiler.libraries.ldflags=
    
    This sets a default definition of that property for cases when it is not automatically defined by the Arduino build system, which would otherwise result in a compilation failure.

Arduino IDE support

Precompiled libraries are only supported in Arduino IDE 1.8.6 and newer, so the users of your library won't be able to use it with outdated versions of the Arduino IDE.

1 Like