Skip to content
This repository was archived by the owner on Apr 17, 2023. It is now read-only.

Libraries

Timor Gruber edited this page Sep 20, 2018 · 7 revisions

One of Arduino's most important features, as with any development system, are libraries. Arduino has 3 different types of libraries:

  1. Built-in Libraries - Libraries included as part of the SDK or a custom platform.
    These libraries conform to a certain format/standard determined by Arduino. For that reason they're also called "Arduino Libraries" in the Arduino-CMake terminology.
    Besides, they consist only of sources - There are no pre-built binaries whatsoever.
  2. 3rd Party Libraries - Libraries that conform to the Arduino standard, but are not part of the SDK.
    These must include the library.properties file under their root directory and provide sources.
    These libraries are usually located under Arduino IDE's Sketchbook Path if they were downloaded with the Library Manager.
    These libraries can also be called "Arduino Libraries".
  3. User Libraries - Libraries that don't conform to the Arduino standard.
    These libraries should be architecture and OS agnostic, and hopefully restrain from any heap-oriented code (such as malloc). They should also provide sources instead of pre-built binaries.

Some of you have already noticed that Arduino-CMake takes an approach similar to CMake itself regarding the targets API, that is of course to ease the use of the framework.
Libraries are no different. How?
In general, to use a certain library in your CMake project you must follow the following procedure:

  1. Either find the library or create it yourself.
    Finding a library usually means finding a pre-built binary matching the requirements of the host OS.
  2. Link the library target to some other target.

We've emphasized usually because as described earlier, Arduino libraries are almost always unbuilt sources. In our case, the library target will always be created and built by the project itself.

Arduino-CMake takes a similar approach.
The following passages relate to the different types of libraries and how to use them:

Built-in Arduino Libraries

These libraries have to be found at first, then linked to another target, preferably the executable target.
To find a library, one should call the find_arduino_library function. It accepts the following parameters:

Order Name Description Required?
1st _target_name Library's target name as it will be registered by CMake. Yes
2nd _library_name Name of the library to search for.
This is actually the name of the library's root directory.
Name can be case-insensitive when searching Built-in Libraries, must be case-sensitive when searching 3rd Party libraries.
Yes
3rd _board_id Hardware Board's ID as retrieved by the get_board_id function. Yes
- 3RD_PARTY Whether the searched library should be treated as a 3rd Party library No

Then, to link it, one would call the link_arduino_library function. It accepts the following parameters:

Order Name Description
1st _target_name Name of the target to link to, usually an executable created with add_arduino_executable
2nd _library_target_name Name of a library target. If it's an Arduino Library, it's the name found earlier with find_arduino_library.
Otherwise, it's the target created with CMake's add_library.
3rd _board_id Hardware Board's ID as retrieved by the get_board_id function.

The following example shows how the Stepper, Servo and Ethernet libraries are included in a project:

find_arduino_library(stepper_lib Stepper ${board_id})
link_arduino_library(my_target stepper_lib ${board_id})

find_arduino_library(servo_lib Servo ${board_id})
link_arduino_library(my_target servo_lib ${board_id})

find_arduino_library(ethernet_lib Ethernet ${board_id})
link_arduino_library(my_target ethernet_lib ${board_id})

Note that the example above assumes the my_target target has already been created earlier.
Also, board's ID has been retrieved as well.

3rd Party Arduino Libraries

As well as Built-in Libraries, these should be found first and then linked to another target. However, they can also be stored inside Arduino IDE's Sketchbook Location, controlled by the ARDUINO_CMAKE_SKETCHBOOK_PATH variable.
By default this variable is automatically set to the location configured in Arduino IDE, however, this option could be turned off by setting the option AUTO_SET_SKETCHBOOK_PATH to OFF.
The ARDUINO_CMAKE_SKETCHBOOK_PATH variable could then be passed a custom location, and that would be used to find 3rd Party libraries in instead.

The Arduino-CMake framework renames every given Arduino-Library name to an Arduino-Compliant name, which is PascalCase.
However, 3rd Party libraries don't always conform to this naming standard (e.g the Adafruit_NeoPixel library), which creates an invalid symbol to search for the framework.
In order to avoid this behavior, one should pass the 3RD_PARTY option to the find_arduino_library function.

User Libraries

A user library's sources could be located anywhere in the host system, without any constraints.
It is the user's responsibility to "fond" them and pass their paths to the framework.

It's considered good practice to keep a user library's sources under the project's scope, especially if that library is created solely for the project at hand. It also makes it easy to "find" it.

As explained above, the library isn't found like an Arduino Library, thus no library target is magically created by some search process. Instead, the library should be created manually.
Creating a library target is really straightforward since it requires just the CMake library API!
To create a library, one would call the add_library function.

Since the library is manually created using CMake's API, it also requires the user to manually specify include directories, so that other targets linking the library will have access to its' headers.
This is done by calling the target_include_directories function, passing the name of the library target created earlier with add_library, a PUBLIC scope (So it will have effect during linkage) and the header directories themselves.
e.g target_include_directories(my_library_target PUBLIC include) where include is the directory containing all public headers.

At last, the library target should be linked to an existing target, just as you would do with an Arduino library.

The following is a list of common and recommended places where user libraries should be stored:

  1. Inside the project's root directory, under a sub-directory named after the library.
    Example:

    |-Project Root
    	|-Library
    		|-include
    			|-Library.h
    		|-src
    			|-Library.c
    
  2. Inside the project's root directory, under a sub-directory named dependencies where all other user libraries are located.
    Note: This is recommended only for 3rd party user libraries, i.e. libraries that weren't created by the user itself.

The following example shows how a user library named Robotics is included in the project:

set(Robotics_lib_path ${CMAKE_SOURCE_DIR}/dependencies/Robotics-1.2)
add_library(Robotics_lib STATIC ${Robotics_lib_path}/src/Robotics.c)
target_include_directories(Robotics_lib PUBLIC ${Robotics_lib_path}/include)
link_arduino_library(my_target Robotics_lib ${board_id})

Where ${CMAKE_SOURCE_DIR} is the parent directory of the project's main CMakeLists.txt file.
The directory structure of the example is as follows:

|-Project Root
	|-dependencies
		|-include
			|-Robotics.h
		|-src
			|-Robotics.c
	|-src
	|-CMakeLists.txt

Note that the example above assumes the my_target target has already been created earlier.
Also, board's ID has been retrieved as well.

Clone this wiki locally