├── .gitignore ├── .vscode └── cmake-kits.json ├── CMakeLists.txt ├── LICENSE ├── README.md ├── blink.cpp ├── cmake ├── arduino_core.cmake ├── arduino_hex.cmake ├── arduino_upload.cmake ├── lto.cmake └── toolchain │ ├── avr.toolchain.cmake │ ├── leonardo.toolchain.cmake │ ├── mega.toolchain.cmake │ └── uno.toolchain.cmake └── images ├── selecting.png └── uploading.png /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | build -------------------------------------------------------------------------------- /.vscode/cmake-kits.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Leonardo", 4 | "toolchainFile": "${workspaceFolder}/cmake/toolchain/leonardo.toolchain.cmake" 5 | }, 6 | { 7 | "name": "UNO", 8 | "toolchainFile": "${workspaceFolder}/cmake/toolchain/uno.toolchain.cmake" 9 | }, 10 | { 11 | "name": "Mega 2560", 12 | "toolchainFile": "${workspaceFolder}/cmake/toolchain/mega.toolchain.cmake" 13 | } 14 | ] -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | project(Blink LANGUAGES C CXX ASM) 3 | 4 | include(cmake/lto.cmake) 5 | include(cmake/arduino_core.cmake) 6 | include(cmake/arduino_hex.cmake) 7 | include(cmake/arduino_upload.cmake) 8 | 9 | add_executable(blink blink.cpp) 10 | target_link_libraries(blink PUBLIC ArduinoCore) 11 | target_compile_options(blink PRIVATE 12 | "-Wall" 13 | "-Wextra" 14 | "-pedantic" 15 | ) 16 | arduino_avr_hex(blink) 17 | 18 | set(ARDUINO_PORT "/dev/ttyACM0" 19 | CACHE STRING "The serial port for uploading using avrdude") 20 | arduino_avr_upload(blink ${ARDUINO_PORT}) 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 PieterP 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arduino AVR CMake 2 | 3 | Compile Arduino AVR programs using CMake. 4 | 5 | ## Instructions 6 | 7 | 1. Clone this repository and open a terminal in the `Arduino-AVR-CMake` folder. 8 | 2. Ensure that the Arduino AVR core is installed correctly, this guide assumes 9 | that the core is in `~/.arduino15/packages/arduino/hardware/avr/1.8.6`, 10 | that the toolchain is in `~/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7`, 11 | and that avrdude is in `~/.arduino15/packages/arduino/tools/avrdude/6.3.0-arduino17`. 12 | If this is not the case, change it now in `cmake/toolchain/avr.toolchain.cmake`. 13 | 3. Configure the project using CMake by running the following command: 14 | ```sh 15 | cmake -S. -Bbuild \ 16 | -D ARDUINO_PORT=/dev/ttyACM0 \ 17 | -D CMAKE_TOOLCHAIN_FILE=cmake/toolchain/uno.toolchain.cmake \ 18 | -D CMAKE_BUILD_TYPE=MinSizeRel 19 | ``` 20 | Customize the port, toolchain file, and build type for your specific 21 | configuration. 22 | 4. Finally, build and upload the example “blink” program: 23 | ```sh 24 | cmake --build build -j -t upload-blink 25 | ``` 26 | To compile the program without uploading, you can use 27 | ```sh 28 | cmake --build build -j -t blink 29 | ``` 30 | If you're using an Arduino with a native USB interface (e.g. Leonardo), 31 | you'll have to press the reset button before uploading. You could 32 | automate this by opening its serial port at 1200 baud as part of the 33 | upload process. 34 | 35 | ## VSCode 36 | 37 | In VSCode, you can select the board you want to use using the 38 | `CMake: Select a Kit` command from the CMake Tools extension. 39 | Then select the right board as shown in the following image: 40 | ![Selecting the Arduino board using CMake](images/selecting.png) 41 | 42 | To build the sketch, you can either press F7 or click the `Build` 43 | button in the bottom ribbon or in the CMake side panel. To upload, you can use 44 | the `upload-blink` utility in the CMake side panel: 45 | ![Uploading the Arduino board using CMake](images/uploading.png) 46 | -------------------------------------------------------------------------------- /blink.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void setup() { 4 | Serial.begin(115200); 5 | delay(2000); 6 | Serial.println("Hello, world!"); 7 | pinMode(LED_BUILTIN, OUTPUT); 8 | } 9 | 10 | void loop() { 11 | digitalWrite(LED_BUILTIN, HIGH); 12 | delay(500); 13 | digitalWrite(LED_BUILTIN, LOW); 14 | delay(500); 15 | } 16 | -------------------------------------------------------------------------------- /cmake/arduino_core.cmake: -------------------------------------------------------------------------------- 1 | if(NOT ARDUINO_PATH) 2 | message(FATAL_ERROR "Arduino-specific variables are not set. \ 3 | Did you select the right toolchain file?") 4 | endif() 5 | 6 | # Basic compilation flags 7 | add_library(ArduinoFlags INTERFACE) 8 | target_compile_options(ArduinoFlags INTERFACE 9 | "-fno-exceptions" 10 | "-ffunction-sections" 11 | "-fdata-sections" 12 | "$<$:-fno-threadsafe-statics>" 13 | "-mmcu=${ARDUINO_MCU}" 14 | ) 15 | target_compile_definitions(ArduinoFlags INTERFACE 16 | "F_CPU=${ARDUINO_F_CPU}" 17 | "ARDUINO=${ARDUINO_VERSION}" 18 | "ARDUINO_${ARDUINO_BOARD}" 19 | "ARDUINO_ARCH_AVR" 20 | ) 21 | target_link_options(ArduinoFlags INTERFACE 22 | "-mmcu=${ARDUINO_MCU}" 23 | "-fuse-linker-plugin" 24 | "LINKER:--gc-sections" 25 | ) 26 | target_compile_features(ArduinoFlags INTERFACE cxx_std_11 c_std_11) 27 | 28 | # Arduino Core 29 | add_library(ArduinoCore STATIC 30 | ${ARDUINO_CORE_PATH}/abi.cpp 31 | ${ARDUINO_CORE_PATH}/CDC.cpp 32 | ${ARDUINO_CORE_PATH}/HardwareSerial0.cpp 33 | ${ARDUINO_CORE_PATH}/HardwareSerial1.cpp 34 | ${ARDUINO_CORE_PATH}/HardwareSerial2.cpp 35 | ${ARDUINO_CORE_PATH}/HardwareSerial3.cpp 36 | ${ARDUINO_CORE_PATH}/HardwareSerial.cpp 37 | ${ARDUINO_CORE_PATH}/IPAddress.cpp 38 | ${ARDUINO_CORE_PATH}/main.cpp 39 | ${ARDUINO_CORE_PATH}/new.cpp 40 | ${ARDUINO_CORE_PATH}/PluggableUSB.cpp 41 | ${ARDUINO_CORE_PATH}/Print.cpp 42 | ${ARDUINO_CORE_PATH}/Stream.cpp 43 | ${ARDUINO_CORE_PATH}/Tone.cpp 44 | ${ARDUINO_CORE_PATH}/USBCore.cpp 45 | ${ARDUINO_CORE_PATH}/WMath.cpp 46 | ${ARDUINO_CORE_PATH}/WString.cpp 47 | ${ARDUINO_CORE_PATH}/hooks.c 48 | ${ARDUINO_CORE_PATH}/WInterrupts.c 49 | ${ARDUINO_CORE_PATH}/wiring_analog.c 50 | ${ARDUINO_CORE_PATH}/wiring.c 51 | ${ARDUINO_CORE_PATH}/wiring_digital.c 52 | ${ARDUINO_CORE_PATH}/wiring_pulse.c 53 | ${ARDUINO_CORE_PATH}/wiring_shift.c 54 | ${ARDUINO_CORE_PATH}/wiring_pulse.S 55 | ) 56 | target_link_libraries(ArduinoCore PUBLIC ArduinoFlags) 57 | target_compile_features(ArduinoCore PUBLIC cxx_std_11 c_std_11) 58 | target_include_directories(ArduinoCore PUBLIC 59 | ${ARDUINO_CORE_PATH} 60 | ${ARDUINO_AVR_PATH}/variants/${ARDUINO_VARIANT} 61 | ) 62 | if(ARDUINO_USB) 63 | target_compile_definitions(ArduinoCore PUBLIC 64 | USB_VID=${ARDUINO_USB_VID} 65 | USB_PID=${ARDUINO_USB_PID} 66 | USB_MANUFACTURER=\"Unknown\" 67 | USB_PRODUCT=\"${ARDUINO_USB_PRODUCT}\" 68 | ) 69 | endif() -------------------------------------------------------------------------------- /cmake/arduino_hex.cmake: -------------------------------------------------------------------------------- 1 | # Transforms the target.elf file into target.eep (EEPROM) and target.hex files. 2 | # Also prints the size of each section in target.elf. 3 | function(arduino_avr_hex target) 4 | set_target_properties(${target} PROPERTIES SUFFIX ".elf") 5 | add_custom_command(TARGET ${target} POST_BUILD 6 | COMMAND ${CMAKE_SIZE} ARGS 7 | -A "$" 8 | USES_TERMINAL) 9 | add_custom_command(TARGET ${target} POST_BUILD 10 | BYPRODUCTS ${target}.eep 11 | COMMAND ${CMAKE_OBJCOPY} ARGS 12 | -O ihex -j .eeprom 13 | --set-section-flags=.eeprom=alloc,load 14 | --no-change-warnings --change-section-lma 15 | .eeprom=0 16 | "$" 17 | ${target}.eep) 18 | add_custom_command(TARGET ${target} POST_BUILD 19 | BYPRODUCTS ${target}.hex 20 | COMMAND ${CMAKE_OBJCOPY} ARGS 21 | -O ihex -R .eeprom 22 | "$" 23 | ${target}.hex) 24 | endfunction() -------------------------------------------------------------------------------- /cmake/arduino_upload.cmake: -------------------------------------------------------------------------------- 1 | # Creates a target upload-target that uses avrdude to upload target.hex to the 2 | # given serial port. 3 | function(arduino_avr_upload target port) 4 | add_custom_target(upload-${target} 5 | COMMAND ${ARDUINO_AVRDUDE} 6 | -C${ARDUINO_AVRDUDE_CONF} 7 | -p${ARDUINO_MCU} 8 | -c${ARDUINO_AVRDUDE_PROTOCOL} 9 | -P${port} 10 | -b${ARDUINO_AVRDUDE_SPEED} 11 | -D 12 | "-Uflash:w:$.hex:i" 13 | USES_TERMINAL) 14 | add_dependencies(upload-${target} ${target}) 15 | endfunction() -------------------------------------------------------------------------------- /cmake/lto.cmake: -------------------------------------------------------------------------------- 1 | # Enables interprocedural optimization (link-time optimization) globally if 2 | # available. 3 | include(CheckIPOSupported) 4 | check_ipo_supported(RESULT ipo_supported OUTPUT ipo_error) 5 | if(ipo_supported) 6 | set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) 7 | else() 8 | message(STATUS "IPO / LTO not supported: ${ipo_error}") 9 | endif() -------------------------------------------------------------------------------- /cmake/toolchain/avr.toolchain.cmake: -------------------------------------------------------------------------------- 1 | # Enter CMake cross-compilation mode 2 | set(CMAKE_SYSTEM_NAME Generic) 3 | set(CMAKE_SYSTEM_PROCESSOR avr) 4 | 5 | # User settings with sensible defaults 6 | set(ARDUINO_PATH "$ENV{HOME}/.arduino15/packages/arduino" CACHE PATH 7 | "Path of the Arduino packages folder, e.g. ~/.arduino15/packages/arduino.") 8 | set(ARDUINO_CORE_VERSION "1.8.6" CACHE STRING 9 | "Version of arduino/ArduinoCore-AVR") 10 | set(AVR_GCC_VERSION "7.3.0-atmel3.6.1-arduino7" CACHE STRING 11 | "Full version string of the GCC release shipped with the Arduino core.") 12 | set(AVRDUDE_VERSION "6.3.0-arduino17" CACHE STRING 13 | "Full version string of the avrdude release shipped with the Arduino core.") 14 | set(ARDUINO_VERSION "10815" CACHE STRING 15 | "Arduino IDE version (used for the macro with the same name)") 16 | 17 | # Derived paths 18 | set(ARDUINO_AVR_PATH ${ARDUINO_PATH}/hardware/avr/${ARDUINO_CORE_VERSION}) 19 | set(ARDUINO_CORE_PATH ${ARDUINO_AVR_PATH}/cores/arduino) 20 | set(ARDUINO_TOOLS_PATH ${ARDUINO_PATH}/tools/avr-gcc/${AVR_GCC_VERSION}/bin) 21 | set(ARDUINO_AVRDUDE_PATH ${ARDUINO_PATH}/tools/avrdude/${AVRDUDE_VERSION}) 22 | set(ARDUINO_AVRDUDE_CONF ${ARDUINO_AVRDUDE_PATH}/etc/avrdude.conf) 23 | 24 | # Toolchain paths 25 | set(CMAKE_C_COMPILER ${ARDUINO_TOOLS_PATH}/avr-gcc CACHE FILEPATH 26 | "Path to avr-gcc" FORCE) 27 | set(CMAKE_CXX_COMPILER ${ARDUINO_TOOLS_PATH}/avr-g++ CACHE FILEPATH 28 | "Path to avr-g++" FORCE) 29 | set(CMAKE_OBJCOPY ${ARDUINO_TOOLS_PATH}/avr-objcopy CACHE FILEPATH 30 | "Path to avr-objcopy" FORCE) 31 | set(CMAKE_SIZE ${ARDUINO_TOOLS_PATH}/avr-size CACHE FILEPATH 32 | "Path to avr-size" FORCE) 33 | set(ARDUINO_AVRDUDE ${ARDUINO_AVRDUDE_PATH}/bin/avrdude CACHE FILEPATH 34 | "Path to avrdude" FORCE) 35 | 36 | # Only look libraries etc. in the sysroot, but never look there for programs 37 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 38 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 39 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 40 | set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) 41 | -------------------------------------------------------------------------------- /cmake/toolchain/leonardo.toolchain.cmake: -------------------------------------------------------------------------------- 1 | set(ARDUINO_BOARD "AVR_LEONARDO") 2 | set(ARDUINO_MCU "atmega32u4") 3 | set(ARDUINO_F_CPU "16000000L") 4 | set(ARDUINO_VARIANT "leonardo") 5 | set(ARDUINO_AVRDUDE_PROTOCOL "avr109") 6 | set(ARDUINO_AVRDUDE_SPEED "57600") 7 | set(ARDUINO_USB On) 8 | set(ARDUINO_USB_VID "0x2341") 9 | set(ARDUINO_USB_PID "0x8036") 10 | set(ARDUINO_USB_PRODUCT "Arduino Leonardo") 11 | 12 | include(${CMAKE_CURRENT_LIST_DIR}/avr.toolchain.cmake) -------------------------------------------------------------------------------- /cmake/toolchain/mega.toolchain.cmake: -------------------------------------------------------------------------------- 1 | set(ARDUINO_BOARD "AVR_MEGA2560") 2 | set(ARDUINO_MCU "atmega2560") 3 | set(ARDUINO_F_CPU "16000000L") 4 | set(ARDUINO_VARIANT "mega") 5 | set(ARDUINO_AVRDUDE_PROTOCOL "wiring") 6 | set(ARDUINO_AVRDUDE_SPEED "115200") 7 | set(ARDUINO_USB Off) 8 | 9 | include(${CMAKE_CURRENT_LIST_DIR}/avr.toolchain.cmake) -------------------------------------------------------------------------------- /cmake/toolchain/uno.toolchain.cmake: -------------------------------------------------------------------------------- 1 | set(ARDUINO_BOARD "AVR_UNO") 2 | set(ARDUINO_MCU "atmega328p") 3 | set(ARDUINO_F_CPU "16000000L") 4 | set(ARDUINO_VARIANT "standard") 5 | set(ARDUINO_AVRDUDE_PROTOCOL "arduino") 6 | set(ARDUINO_AVRDUDE_SPEED "115200") 7 | set(ARDUINO_USB Off) 8 | 9 | include(${CMAKE_CURRENT_LIST_DIR}/avr.toolchain.cmake) -------------------------------------------------------------------------------- /images/selecting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tttapa/Arduino-AVR-CMake/eb120a6a3cabedde245ffd673a91325a2ac5c998/images/selecting.png -------------------------------------------------------------------------------- /images/uploading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tttapa/Arduino-AVR-CMake/eb120a6a3cabedde245ffd673a91325a2ac5c998/images/uploading.png --------------------------------------------------------------------------------