Search code examples
clinuxcmakemakefilefreertos

CMake can't find the header from the PICO-SDK


So I've been struggling for hours and I can't find the solution to my problem. A more detailed description of the problem is as follows:

So, I created a "blinking LED" example based on the examples provided by the PICO-SDK (for the Raspberry Pi Pico). That means that I have a "main.c" as my main source (or executable, in terms of CMake). But every time that I try to move code from the main.c to a different C file (to make the whole project more portable) I always have the same problem, which is that the resulting C file can't find a header file.

I tried hardcoding the header file by giving the absolute path, but then that header also points to different headers and the problem repeats itself.

Here's the folder structure of the source files:

main_directory:
├── build
├── CMakeLists.txt
├── FreeRTOS-Kernel
├── include
│   ├── FreeRTOSConfig.h
│   └── main.h
├── lib
│   ├── blinkingLED
│   │   ├── blinkingLED.c <~ CMake fails in this file
│   │   ├── blinkingLED.h
│   │   └── CMakeLists.txt
│   └── serial
├── pico_sdk_import.cmake
├── src
    └── main.c

and the structure for the pico-sdk:

kali:
|-pico-sdk
|-main_directory

So, the reproducible example is this (by file)

CMakeLists.txt (principal):
cmake_minimum_required(VERSION 3.19)
include(pico_sdk_import.cmake)
project(FRTOSTest C CXX ASM)
pico_sdk_init()
add_executable(FRTOSTest src/main.c)
FILE(GLOB FreeRTOS_src FreeRTOS-Kernel/*.c)
add_library(FreeRTOS STATIC ${FreeRTOS_src}
            FreeRTOS-Kernel/portable/GCC/ARM_CM0/port.c
            FreeRTOS-Kernel/portable/MemMang/heap_4.c
            src/blinkingLED.c)
target_include_directories(FreeRTOS PUBLIC FreeRTOS-Kernel/include
                            include/
                            FreeRTOS-Kernel/portable/GCC/ARM_CM0/)
target_link_libraries(FRTOSTest 
                    pico_stdlib 
                    hardware_gpio 
                    FreeRTOS)
pico_enable_stdio_usb(FRTOSTest 1)
pico_enable_stdio_uart(FRTOSTest 0)
pico_add_extra_outputs(FRTOSTest)

The main.c file:

#include <stdlib.h>
#include "pico/stdlib.h" // this header is being 'mapped' correctly
// ...
int main(void) { /* code */ }

Then the other CMakeLists.txt (from the folder lib/blinkingLED):

include(../../pico_sdk_import.cmake)
add_library(blinkingLED STATIC blinkingLED.c)
target_include_directories(blinkingLED PUBLIC ./ ${PICO_SDK_PATH})

The blinkingLED.c file:

#include "pico/stdlib.h" // This line is causing the compilation failure
// ...
void foo(void) { /* using some macros and definitions from that library */ }

And the error that I get is something along the line of:

blinkingLED.c(1:20) cannot find the file "pico/stdlib.h"

Solution

  • Scope is a tricky thing in CMAKE. There is a pretty solid explanation of it here if you want to read a little bit more.

    For your top-level CMAKELists.txt file, your goal is to link your portable library and not compile it as part of the source for the freeRTOS library. Adding the directory of your library to the target_include_directories will add the LED library's CMAKElists.txt to the CMAKE build tree. Linking the target created by that CMAKElists.txt [blinkingLED] via target_link_libraries provides access to your executable target. Those changes looks like this.

    CMakeLists.txt (principal):
    cmake_minimum_required(VERSION 3.19)
    include(pico_sdk_import.cmake)
    project(FRTOSTest C CXX ASM)
    pico_sdk_init()
    add_executable(FRTOSTest src/main.c)
    FILE(GLOB FreeRTOS_src FreeRTOS-Kernel/*.c)
    add_library(FreeRTOS STATIC ${FreeRTOS_src}
                FreeRTOS-Kernel/portable/GCC/ARM_CM0/port.c
                FreeRTOS-Kernel/portable/MemMang/heap_4.c
               )
    target_include_directories(FreeRTOS PUBLIC FreeRTOS-Kernel/include
                                include/
                                FreeRTOS-Kernel/portable/GCC/ARM_CM0/
                                lib/blinkingLED
                              )
    target_link_libraries(FRTOSTest 
                        pico_stdlib 
                        hardware_gpio 
                        FreeRTOS
                        blinkingLED
                        )
    pico_enable_stdio_usb(FRTOSTest 1)
    pico_enable_stdio_uart(FRTOSTest 0)
    pico_add_extra_outputs(FRTOSTest)
    

    For the blinkingLED CMAKElists.txt file, you need to make sure you are providing the pico stdlib within its scope. This needs to be done with target_link_libraries. What you had previously tried to do was to add the picoSDK source directory to the source files of your blinkingLED.

    include(../../pico_sdk_import.cmake)
    add_library(blinkingLED STATIC blinkingLED.c)
    target_sources(blinkingLED 
                   "blinkingLED.h"
                   "blinkingLED.c"
                   )
    target_link_libraries(blinkingLED LINK_PUBLIC
                          pico_stdlib
                          hardware_gpio
                          )