Merge branch 'feature/prebuilt_binary_example' into 'master'

cmake: import prebuilt library

See merge request espressif/esp-idf!6838
This commit is contained in:
Angus Gratton 2019-12-13 13:36:47 +08:00
commit 40b657d4fe
13 changed files with 181 additions and 0 deletions

View File

@ -1010,6 +1010,28 @@ Espressif's fork of `mbedtls <https://github.com/ARMmbed/mbedtls>`_. See its :co
The CMake variable ``ESP_PLATFORM`` is set to 1 whenever the ESP-IDF build system is being used. Tests such as ``if (ESP_PLATFORM)`` can be used in generic CMake code if special IDF-specific logic is required.
Using Prebuilt Libraries with Components
========================================
.. highlight:: cmake
The ESP-IDF build system provides a utility function ``add_prebuilt_library`` for users to be able to easily import and use
prebuilt libraries::
add_prebuilt_library(target_name lib_path [REQUIRES req1 req2 ...] [PRIV_REQUIRES req1 req2 ...])
where:
- ``target_name``- name that can be used to reference the imported library, such as when linking to other targets
- ``lib_path``- path to prebuilt library; may be an absolute or relative path to the component directory
Optional arguments ``REQUIRES`` and ``PRIV_REQUIRES`` specify dependency on other components. These have the same meaning as the arguments for ``idf_component_register``.
Take note that the prebuilt library must have been compiled for the same target as the consuming project. Configuration relevant to the prebuilt
library must also match. If not paid attention to, these two factors may contribute to subtle bugs in the app.
For an example, take a look at :example:`build_system/cmake/import_prebuilt`.
Using ESP-IDF in Custom CMake Projects
======================================

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(import_prebuilt)

View File

@ -0,0 +1,37 @@
# Import Prebuilt Library Example
This example illustrates how to import a prebuilt static library in the ESP-IDF build system.
## Example Flow
Users need to first build the project in the [prebuilt](prebuilt) subdirectory:
```
cd prebuilt
idf.py build
```
This builds a component named [prebuilt](prebuilt/components/prebuilt), which has private dependency on ESP-IDF components `spi_flash`, `log` and `app_update` (see [its CMakeLists.txt](prebuilt/components/prebuilt/CMakeLists.txt)). Once built, the archive file `libprebuilt.a`, along with the header file `prebuilt.h`, is automatically copied to the [`main` component](main) of this example project.
The [`main` component's CMakeLists.txt](main/CMakeLists.txt) demonstrates how to import `libprebuilt.a` and link it to `main` so that the definitions inside can be used.
It also demonstrates how to specify the same dependencies the original component had so as to properly resolve symbols used inside the prebuilt library.
Users can then return to this directory and build the main example:
```
cd ..
idf.py build
```
### Output
The example simply outputs the current running partition.
```
I (319) prebuilt: The running partition is 'factory'!
```
---
There is a discussion on importing prebuilt libraries in the programming guide under `API Guides` -> `Build System` -> `Using Prebuilt Libraries with Components`

View File

@ -0,0 +1,12 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS ".")
# Import the library, specifying a target name and the library path.
# The private dependencies of the library is also specified.
add_prebuilt_library(prebuilt "libprebuilt.a"
PRIV_REQUIRES spi_flash app_update log)
# `main` calls a function from the library, so link it to `main`
target_link_libraries(${COMPONENT_LIB} PRIVATE prebuilt)

View File

@ -0,0 +1,17 @@
/* Import Prebuilt Library Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
// Include the prebuilt library's header file so as to be able
// to reference `prebuilt_func` here.
#include "prebuilt.h"
void app_main(void)
{
prebuilt_func();
}

View File

@ -0,0 +1,6 @@
# For users checking this example, ignore the following code. This is so that
# the prebuilt project is built automatically in ESP-IDF CI.
if("$ENV{CI}")
execute_process(COMMAND ${IDFTOOL} build
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/prebuilt)
endif()

View File

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.5)
# Since we're only interested in the prebuilt library, trim
# the build
set(COMPONENTS prebuilt main esptool_py)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(prebuilt C)

View File

@ -0,0 +1,10 @@
idf_component_register(SRCS prebuilt.c
INCLUDE_DIRS "."
PRIV_REQUIRES app_update spi_flash log)
# After build, copy the archive file and header file to parent example directory's main component
add_custom_command(TARGET ${COMPONENT_LIB}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${COMPONENT_LIB}> ${CMAKE_SOURCE_DIR}/../main
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_LIST_DIR}/prebuilt.h ${CMAKE_SOURCE_DIR}/../main
COMMENT "Copying built archive file and header to parent example directory...")

View File

@ -0,0 +1,21 @@
/* Import Prebuilt Library Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "esp_ota_ops.h"
#include "esp_partition.h"
#include "esp_log.h"
const char *TAG = "prebuilt";
void prebuilt_func(void)
{
const esp_partition_t* running_partition = esp_ota_get_running_partition();
ESP_LOGI(TAG, "The running partition is '%s'!", running_partition->label);
}

View File

@ -0,0 +1,11 @@
/* Import Prebuilt Library Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
void prebuilt_func(void);

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "")

View File

@ -0,0 +1,6 @@
#include <stdio.h>
void app_main(void)
{
printf("Hello World!\n");
}

View File

@ -258,3 +258,26 @@ function(add_c_compile_options)
add_compile_options($<$<COMPILE_LANGUAGE:C>:${option}>)
endforeach()
endfunction()
function(add_prebuilt_library target_name lib_path)
cmake_parse_arguments(_ "" "" "REQUIRES;PRIV_REQUIRES" ${ARGN})
get_filename_component(lib_path "${lib_path}"
ABSOLUTE BASE_DIR "${CMAKE_CURRENT_LIST_DIR}")
add_library(${target_name} STATIC IMPORTED)
set_property(TARGET ${target_name} PROPERTY IMPORTED_LOCATION ${lib_path})
foreach(req ${__REQUIRES})
idf_component_get_property(req_lib "${req}" COMPONENT_LIB)
set_property(TARGET ${target_name} APPEND PROPERTY LINK_LIBRARIES "${req_lib}")
set_property(TARGET ${target_name} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "${req_lib}")
endforeach()
foreach(req ${__PRIV_REQUIRES})
idf_component_get_property(req_lib "${req}" COMPONENT_LIB)
set_property(TARGET ${target_name} APPEND PROPERTY LINK_LIBRARIES "${req_lib}")
set_property(TARGET ${target_name} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "$<LINK_ONLY:${req_lib}>")
endforeach()
endfunction()