Arduino_Core_STM32 icon indicating copy to clipboard operation
Arduino_Core_STM32 copied to clipboard

cmake build fails if more than one build_sketch definition is used

Open ddowling opened this issue 1 year ago • 7 comments

I am trying to build multiple sketches using a project wide CMakeLists.txt file. If I call the build_sketch() function with each of the targets then cmake reports an error about duplicated targets:

...
Make Error at /home/dpd/.arduino15/packages/STMicroelectronics/hardware/stm32/2.7.1/variants/STM32F1xx/F103C8T_F103CB(T-U)/CMakeLists.txt:5 (add_library):
  add_library cannot create target "variant" because another target with the
  same name already exists.  The existing target is an interface library
  created in source directory
  "/home/dpd/.arduino15/packages/STMicroelectronics/hardware/stm32/2.7.1/variants/STM32F1xx/F103C8T_F103CB(T-U)".
  See documentation for policy CMP0002 for more details.
...

I have tried various cmake property settings but the error persists. I was able to get the builds to work by putting an if (NOT TARGET variant) guard around the add_subdirectory calls in build_sketch.cmake.

*** build_sketch.cmake.orig	2024-02-21 17:32:23.290460959 +1100
--- build_sketch.cmake	2024-02-21 17:33:09.851221766 +1100
***************
*** 6,14 ****
  include(set_base_arduino_config)
  
  function(build_sketch)
!   add_subdirectory(${BUILD_VARIANT_PATH} ./variant)
!   add_subdirectory(${BUILD_CORE_PATH} ./cores/arduino)
!   add_subdirectory(${BUILD_LIB_PATH} ./libraries)
  
    cmake_parse_arguments(PARSE_ARGV 0 SKBD "" "TARGET" "SOURCES;DEPENDS")
  
--- 6,17 ----
  include(set_base_arduino_config)
  
  function(build_sketch)
!   if (NOT TARGET variant)
!     add_subdirectory(${BUILD_VARIANT_PATH} ./variant)
!     add_subdirectory(${BUILD_CORE_PATH} ./cores/arduino)
!     add_subdirectory(${BUILD_LIB_PATH} ./libraries)
!   endif()
! 
  
    cmake_parse_arguments(PARSE_ARGV 0 SKBD "" "TARGET" "SOURCES;DEPENDS")

If there is a better solution then I would love to know otherwise I can submit a pull request.

ddowling avatar Feb 21 '24 06:02 ddowling

@massonal any input for this? Did you try build with several sketches? Thanks.

fpistm avatar Feb 21 '24 06:02 fpistm

Hello,

IIRC build_sketch() creates build targets with specific names to handle the Arduino workflow. These targets always have the same conventional name, so that they can be more easily integrated into the rest of the project. (variant is one, there are others.)

Unfortunately, this means than no more than one sketch is supported per CMake project.

I think it's possible to change the name of the conventional targets to include some sketch-specific prefix. If you're interested in developing this, please feel free! - assuming @fpistm agrees on the idea ;)

massonal avatar Feb 21 '24 07:02 massonal

The targets that cause a clash seem to be more dependant on the variant selected and this is controlled by set_board and should not really change on a per sketch basis. I thin redefining them in each sketch is the issue.

ddowling avatar Feb 21 '24 08:02 ddowling

You're right. I have studied the issue in a bit more depth, and the limitation you're running into is that each variant has its own CMakeLists.txt file which defines a target named variant.

The simplest solution is, I think, to move the add_subdirectory() calls you pointed out earlier outside of build_sketch() (directly at file level, under include(set_base_arduino_config)). This would have to be thoroughly documented in the wiki, however:

  • importing build_sketch.cmake has side-effects
  • importing build_sketch.cmake should only happen once
  • having several sketches with different targets / configs is not supported.

What do you think about this, @ddowling @fpistm ?

massonal avatar Feb 21 '24 08:02 massonal

Moving the add_subdirectory() calls out of the function definition works in my use-case. If we are concerned about importing build_sketch.cmake more than once the we could use include_guard() on the file. I understand having different configs is not supported but I don't think this would be a very common case. If you were building for different boards or settings this can be handled by having different build directories where cmake is run with different defines. The case I am trying to address is a library with multiple small programs to unit test the functionality and to provide some user examples. When doing embedded development I like to keep a few very small and simple test programs around for when the whole board just starts misbehaving. You need this to determine if you are fighting a software or hardware issue.

ddowling avatar Feb 21 '24 09:02 ddowling

Hey, I'm glad this solution works for you. Also, I did not know about include_guard(); it would definitely be a good addition in most files in stm32duino's CMake framework.

Do you want to implement these changes and propose a pull request?

massonal avatar Feb 21 '24 10:02 massonal

@massonal I just noticed another issue in sketch_preprocess_sources.cmake. If you have an .ino file in a subdirectory the dependency fails. Everything is setup correctly but the filename without the flattened ${CMAKE_CURRENT_BINARY_DIR} path is added to the SRCLIST.

I will get a pull request together with these changes.

*** sketch_preprocess_sources.cmake.orig	2024-02-21 20:52:30.297138663 +1100
--- sketch_preprocess_sources.cmake	2024-02-21 21:02:28.738043288 +1100
***************
*** 27,33 ****
          COMPILE_OPTIONS "-include;Arduino.h;-include;${SRCFILE}.h"
          OBJECT_DEPENDS "${SRCFILE}.h"
        )
!       list(APPEND SRCLIST ${SRCFILE}.cpp)
      else()
        list(APPEND SRCLIST ${SRCFILE})
      endif()
--- 27,33 ----
          COMPILE_OPTIONS "-include;Arduino.h;-include;${SRCFILE}.h"
          OBJECT_DEPENDS "${SRCFILE}.h"
        )
!       list(APPEND SRCLIST ${CMAKE_CURRENT_BINARY_DIR}/${SRC_BASE_NAME}.cpp)
      else()
        list(APPEND SRCLIST ${SRCFILE})
      endif()

ddowling avatar Feb 21 '24 10:02 ddowling