|
|
|
#!/usr/bin/env bash
|
|
|
|
# kaleidoscope-builder - Kaleidoscope helper tool
|
|
|
|
# Copyright (C) 2017-2018 Keyboard.io, Inc.
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify it under
|
|
|
|
# the terms of the GNU General Public License as published by the Free Software
|
|
|
|
# Foundation, version 3.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License along with
|
|
|
|
# this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
######
|
|
|
|
###### Build and output configuration
|
|
|
|
######
|
|
|
|
|
|
|
|
identify_os() {
|
|
|
|
|
|
|
|
## Platform-specific overrides
|
|
|
|
# Shamelessly stolen from git's Makefile
|
|
|
|
uname_S=$(uname -s 2>/dev/null || echo not)
|
|
|
|
uname_O=$(uname -o 2>/dev/null || echo not)
|
|
|
|
}
|
|
|
|
|
|
|
|
adjust_for_virtual_build() {
|
|
|
|
if [ "${uname_S}" = "FreeBSD" ]; then
|
|
|
|
: "${COMPILER_PATH:=/usr/local/bin/}"
|
|
|
|
else
|
|
|
|
: "${COMPILER_PATH:=/usr/bin/}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
COMPILER_PREFIX=""
|
|
|
|
}
|
|
|
|
|
|
|
|
adjust_for_cygwin() {
|
|
|
|
# The Windows arduino-builder.exe doesn't understand being told to exec against Cygwin symlinks
|
|
|
|
CCACHE_NOT_SUPPORTED=1
|
|
|
|
|
|
|
|
# It's important that all of these be underneath /cygdrive/c so they can be converted to Windows paths that the
|
|
|
|
# Windows Arduino binaries can understand.
|
|
|
|
: "${TMPDIR:=/cygdrive/c/Users/${USER}/AppData/Local/Temp}"
|
|
|
|
|
|
|
|
# We need to prevent Windows executables from being passed parameters that are absolute paths, since they won't
|
|
|
|
# be interpretable when of the form /cygdrive/c/foo. To work around this, we set the common path root variables
|
|
|
|
# to use relative paths instead of absolute paths, since those have mostly platform-agnostic behavior.
|
|
|
|
#
|
|
|
|
# Note that this trick requires that all of these paths exist on the same drive letter as the current directory,
|
|
|
|
# since otherwise even the relative paths would include Cygwin-specific components. So...
|
|
|
|
if [[ $(realpath --relative-base=/cygdrive/c .) == /* ]]; then
|
|
|
|
echo "kaleidoscope-builder's Cygwin support is currently limited to running from within /cygdrive/c"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
TMPDIR="$(realpath --relative-to=./ ${TMPDIR})"
|
|
|
|
}
|
|
|
|
|
|
|
|
absolute_filename() {
|
|
|
|
echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
|
|
|
|
}
|
|
|
|
|
|
|
|
read_conf_files() {
|
|
|
|
|
|
|
|
for conf_file in \
|
|
|
|
"${HOME}/.kaleidoscope-builder.conf" \
|
|
|
|
"$(pwd)/.kaleidoscope-builder.conf" \
|
|
|
|
"$(pwd)/kaleidoscope-builder.conf"; do
|
|
|
|
if [ -e "${conf_file}" ]; then
|
|
|
|
# shellcheck disable=SC1090
|
|
|
|
. "${conf_file}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
done
|
|
|
|
}
|
|
|
|
configure_arduino_cli_env() {
|
|
|
|
|
|
|
|
SYSTEM_ARDUINO_CLI="$(command -v arduino-cli || true)"
|
|
|
|
|
|
|
|
if [ -z "${SYSTEM_ARDUINO_CLI}" ]; then
|
|
|
|
: "${ARDUINO_CLI:=${KALEIDOSCOPE_BIN_DIR}/arduino-cli}"
|
|
|
|
else
|
|
|
|
: "${ARDUINO_CLI:=${SYSTEM_ARDUINO_CLI}}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
: "${ARDUINO_CONTENT:=${KALEIDOSCOPE_DIR}/.arduino}"
|
|
|
|
: "${ARDUINO_DIRECTORIES_DATA:=${ARDUINO_CONTENT}/data}"
|
|
|
|
: "${ARDUINO_DIRECTORIES_DOWNLOADS:=${ARDUINO_CONTENT}/downloads}"
|
|
|
|
: "${ARDUINO_DIRECTORIES_USER:=${ARDUINO_CONTENT}/user}"
|
|
|
|
: "${ARDUINO_CLI_CONFIG:=${ARDUINO_DIRECTORIES_DATA}/arduino-cli.yaml}"
|
|
|
|
: "${ARDUINO_BOARDS_MANAGER_KALEIDOSCOPE:=https://raw.githubusercontent.com/keyboardio/boardsmanager/master/package_keyboardio_index.json}"
|
|
|
|
}
|
|
|
|
|
|
|
|
install_arduino_cli() {
|
|
|
|
# todo cd to kaleidoscope dir
|
|
|
|
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
|
|
|
|
}
|
|
|
|
|
|
|
|
configure_arduino_cli() {
|
|
|
|
if [ -z "${ARDUINO_CLI}" ]; then
|
|
|
|
install_arduino_cli
|
|
|
|
fi
|
|
|
|
if [ -z "${ARDUINO_CLI_CONFIG}" ]; then
|
|
|
|
install_arduino_cli_config
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
install_arduino_cli_config() {
|
|
|
|
run_arduino_cli config init
|
|
|
|
}
|
|
|
|
|
|
|
|
install_arduino_core_kaleidoscope() {
|
|
|
|
install_arduino_core_avr
|
|
|
|
|
|
|
|
install_arduino_core "keyboardio:avr"
|
|
|
|
}
|
|
|
|
|
|
|
|
install_arduino_core_avr() {
|
|
|
|
install_arduino_core "arduino:avr"
|
|
|
|
}
|
|
|
|
|
|
|
|
install_arduino_core() {
|
|
|
|
run_arduino_cli core install "$1"
|
|
|
|
}
|
|
|
|
|
|
|
|
run_arduino_cli() {
|
|
|
|
ARDUINO_DIRECTORIES_USER=${ARDUINO_DIRECTORIES_USER} \
|
|
|
|
ARDUINO_DIRECTORIES_DATA=${ARDUINO_DIRECTORIES_DATA} \
|
|
|
|
ARDUINO_DIRECTORIES_DOWNLOADS=${ARDUINO_DIRECTORIES_DOWNLOADS} \
|
|
|
|
ARDUINO_BOARD_MANAGER_ADDITIONAL_URLS=${ARDUINO_BOARDS_MANAGER_KALEIDOSCOPE} \
|
|
|
|
"${ARDUINO_CLI}" "$@"
|
|
|
|
}
|
|
|
|
|
|
|
|
build_version() {
|
|
|
|
: "${LIB_PROPERTIES_PATH:="../.."}"
|
|
|
|
GIT_VERSION="$(
|
|
|
|
cd "${SKETCH_DIR}"
|
|
|
|
if [ -d .git ]; then echo -n '-g' && git describe --abbrev=4 --dirty --always; fi
|
|
|
|
)"
|
|
|
|
LIB_VERSION="$(
|
|
|
|
cd "${SKETCH_DIR}"
|
|
|
|
(grep version= "${LIB_PROPERTIES_PATH}/library.properties" 2>/dev/null || echo version=0.0.0) | cut -d= -f2
|
|
|
|
)${GIT_VERSION}"
|
|
|
|
}
|
|
|
|
|
|
|
|
build_paths() {
|
|
|
|
# We need that echo because we\re piping to cksum
|
|
|
|
# shellcheck disable=SC2005
|
|
|
|
SKETCH_IDENTIFIER="$(echo "${SKETCH_FILE_PATH}" | cksum | cut -d ' ' -f 1)-${SKETCH_FILE_NAME}"
|
|
|
|
: "${KALEIDOSCOPE_TEMP_PATH:=${TMPDIR:-/tmp}/kaleidoscope-${USER}}"
|
|
|
|
|
|
|
|
: "${KALEIDOSCOPE_BUILD_PATH:=${KALEIDOSCOPE_TEMP_PATH}/sketch}"
|
|
|
|
: "${KALEIDOSCOPE_OUTPUT_PATH:=${KALEIDOSCOPE_TEMP_PATH}/sketch}"
|
|
|
|
|
|
|
|
: "${SKETCH_OUTPUT_DIR:=${SKETCH_IDENTIFIER}/output}"
|
|
|
|
: "${SKETCH_BUILD_DIR:=${SKETCH_IDENTIFIER}/build}"
|
|
|
|
|
|
|
|
: "${BUILD_PATH:=${KALEIDOSCOPE_BUILD_PATH}/${SKETCH_BUILD_DIR}}"
|
|
|
|
: "${OUTPUT_PATH:=${KALEIDOSCOPE_OUTPUT_PATH}/${SKETCH_OUTPUT_DIR}}"
|
|
|
|
|
|
|
|
: "${CCACHE_WRAPPER_PATH:=${KALEIDOSCOPE_TEMP_PATH}/ccache/bin}"
|
|
|
|
: "${CORE_CACHE_PATH:=${KALEIDOSCOPE_TEMP_PATH}/arduino-cores}"
|
|
|
|
|
|
|
|
mkdir -p "$CORE_CACHE_PATH"
|
|
|
|
mkdir -p "$BUILD_PATH"
|
|
|
|
}
|
|
|
|
|
|
|
|
build_filenames() {
|
|
|
|
: "${OUTPUT_FILE_PREFIX:=${SKETCH_BASE_NAME}-${LIB_VERSION}}"
|
|
|
|
: "${HEX_FILE_PATH:=${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.hex}"
|
|
|
|
: "${HEX_FILE_WITH_BOOTLOADER_PATH:=${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}-with-bootloader.hex}"
|
|
|
|
: "${ELF_FILE_PATH:=${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.elf}"
|
|
|
|
: "${LIB_FILE_PATH:=${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.a}"
|
|
|
|
}
|
|
|
|
|
|
|
|
enable_ccache() {
|
|
|
|
if [ -z "${CCACHE_NOT_SUPPORTED}" ] && [ "$(command -v ccache)" ]; then
|
|
|
|
if ! [ -d "$CCACHE_WRAPPER_PATH" ]; then
|
|
|
|
mkdir -p "$CCACHE_WRAPPER_PATH"
|
|
|
|
|
|
|
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${C_COMPILER_BASENAME}" ]; then
|
|
|
|
ln -s "$(command -v ccache)" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${C_COMPILER_BASENAME}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}" ]; then
|
|
|
|
ln -s "$(command -v ccache)" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}nm" ]; then
|
|
|
|
ln -s "${AVR_NM}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}nm"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}objcopy" ]; then
|
|
|
|
ln -s "${AVR_OBJCOPY}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}objcopy"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}ar" ]; then
|
|
|
|
ln -s "${AVR_AR}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}ar"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}size" ]; then
|
|
|
|
ln -s "${AVR_SIZE}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}size"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
export CCACHE_PATH=${COMPILER_PATH}/
|
|
|
|
CCACHE_ENABLED=1
|
|
|
|
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
firmware_size() {
|
|
|
|
if [ "${ARCH}" = "virtual" ]; then
|
|
|
|
echo "[Size not computed for virtual build]"
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
: "${MAX_PROG_SIZE:=$(get_arduino_pref 'upload.maximum_size')}"
|
|
|
|
|
|
|
|
## This is a terrible hack, please don't hurt me. - algernon
|
|
|
|
|
|
|
|
set +e
|
|
|
|
raw_output=$("$@" 2>/dev/null)
|
|
|
|
rc=$?
|
|
|
|
set -e
|
Add rules and scripts for building on FreeBSD.
* Uses usbconfig to determine the Model 01's USB modem port.
* Works around incompatibe avrsize flags.
You need to be able to run usbconfig to flash the firmware from the
buildtools. This can be accomplished with appropriate groups and devfs
rules.
Requires gmake, perl, avrdude, and (probably) arduino18 from ports.
The version of avrdude in ports uses an avr-size command that doesn't
understand the -C or --mcu flags. From what I can tell, these flags
are uneccessary, as the size computed with them is the same as what
you get from adding up the appropriate segments from the standard
output of avr-size without any flags. However, since the size is only
informative, I've opted to simply check to see if the command
succeeded, and if not, output a string saying it could not be.
It would probably be better to:
* Determine appropriate flags based on build tools, or,
* Just not use the flags at all, and grab the .text, etc., segment
sizes from the standard output and add them up via `dc` for
display.
I've been using this toolchain to build successfully on FreeBSD 12 for
the Model 01 without issue. It should work with earlier versions of
FreeBSD as well.
Signed-off-by: Brian Cully <bjc@kublai.com>
6 years ago
|
|
|
|
|
|
|
if [ $rc -eq 0 ]; then
|
|
|
|
output="$(echo "${raw_output}" | grep "\\(Program\\|Data\\):" | sed -e 's,^, - ,' && echo)"
|
|
|
|
|
|
|
|
PROGSIZE="$(echo "${output}" | grep "Program:" | cut -d: -f2 | awk '{print $1}')"
|
|
|
|
|
|
|
|
PERCENT="$(echo "${PROGSIZE}" "${MAX_PROG_SIZE}" | awk "{ printf \"%02.01f\", \$1 / \$2 * 100 }")"
|
|
|
|
|
|
|
|
# we want the sed there, doing with shell builtins would be worse.
|
|
|
|
# shellcheck disable=SC2001 disable=SC1117
|
|
|
|
echo "${output}" | sed -e "s/\(Program:.*\)(\([0-9\.]*%\) Full)/\1(${PERCENT}% Full)/"
|
|
|
|
else
|
|
|
|
echo "Unable to determine image size."
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
find_sketch() {
|
|
|
|
SKETCH_DIR="${SKETCH:-$(absolute_filename "$(pwd)")}"
|
|
|
|
SKETCH_BASE_NAME=$(basename "${SKETCH_DIR}")
|
|
|
|
SKETCH_FILE_NAME="${SKETCH_BASE_NAME}.ino"
|
|
|
|
|
|
|
|
# Arduino sketches are usually a file inside directory Foo named Foo.ino, so try that as a fallback
|
|
|
|
for dir in \
|
|
|
|
"${SKETCH_DIR}" \
|
|
|
|
"src/" \
|
|
|
|
"."; do
|
|
|
|
if [ -f "${dir}/${SKETCH_FILE_NAME}" ]; then
|
|
|
|
SKETCH_DIR="${dir}"
|
|
|
|
SKETCH_FILE_PATH=$(absolute_filename "${dir}/${SKETCH_FILE_NAME}")
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
echo "I couldn't find your sketch (.ino file)" >&2
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
|
|
|
find_device_vid_pid() {
|
|
|
|
: "${VID:=$(get_arduino_pref 'build.vid')}"
|
|
|
|
: "${SKETCH_PID:=$(get_arduino_pref 'build.pid')}"
|
|
|
|
: "${BOOTLOADER_PID:=$(get_arduino_pref 'bootloader.pid')}"
|
|
|
|
: "${BOOTLOADER_VID:=$(get_arduino_pref 'bootloader.vid')}"
|
|
|
|
}
|
|
|
|
|
|
|
|
prompt_before_flashing() {
|
|
|
|
flashing_instructions=$(get_arduino_pref 'build.flashing_instructions')
|
|
|
|
|
|
|
|
if [ "x${flashing_instructions}x" = "xx" ]; then
|
|
|
|
flashing_instructions="If your keyboard needs you to do something to put it in flashing mode, do that now."
|
|
|
|
fi
|
|
|
|
|
|
|
|
printf '%b\n\n' "${flashing_instructions}"
|
|
|
|
echo ""
|
|
|
|
echo "When you're ready to proceed, press 'Enter'."
|
|
|
|
|
|
|
|
# We do not want to permit line continuations here. We just want a newline.
|
|
|
|
# shellcheck disable=SC2162
|
|
|
|
read
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
flash() {
|
|
|
|
compile "$@"
|
|
|
|
|
|
|
|
# Check to see if we can see a keyboard bootloader port.
|
|
|
|
# If we -can-, then we should skip over the "reset to bootloader" thing
|
|
|
|
find_bootloader_ports
|
|
|
|
if [ -z "${DEVICE_PORT_BOOTLOADER}" ]; then
|
|
|
|
prompt_before_flashing
|
|
|
|
|
|
|
|
# This is defined in the (optional) user config.
|
|
|
|
# shellcheck disable=SC2154
|
|
|
|
${preFlash_HOOKS}
|
|
|
|
fi
|
|
|
|
|
|
|
|
find_device_port
|
|
|
|
run_arduino_cli upload \
|
|
|
|
--fqbn "${FQBN}" \
|
|
|
|
--port "${DEVICE_PORT}" \
|
|
|
|
--verbose
|
|
|
|
|
|
|
|
|
|
|
|
# This is defined in the (optional) user config.
|
|
|
|
# shellcheck disable=SC2154
|
|
|
|
${postFlash_HOOKS}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
flash_from_bootloader() {
|
|
|
|
compile "$@"
|
|
|
|
prompt_before_flashing
|
|
|
|
find_bootloader_ports
|
|
|
|
run_arduino_cli upload \
|
|
|
|
--fqbn "${FQBN}" \
|
|
|
|
--port "${DEVICE_PORT_BOOTLOADER}" \
|
|
|
|
--verbose
|
|
|
|
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
hex_with_bootloader() {
|
|
|
|
compile
|
|
|
|
|
|
|
|
: "${BOOTLOADER_PATH:=$(get_arduino_pref 'runtime.platform.path')/bootloaders/$(get_arduino_pref 'bootloader.file')}"
|
|
|
|
|
|
|
|
awk '/^:00000001FF/ == 0' "${HEX_FILE_PATH}" >"${HEX_FILE_WITH_BOOTLOADER_PATH}"
|
|
|
|
echo "Using ${BOOTLOADER_PATH}"
|
|
|
|
cat "${BOOTLOADER_PATH}" >>"${HEX_FILE_WITH_BOOTLOADER_PATH}"
|
|
|
|
ln -sf -- "${OUTPUT_FILE_PREFIX}-with-bootloader.hex" "${OUTPUT_PATH}/${SKETCH_BASE_NAME}-latest-with-bootloader.hex"
|
|
|
|
cat <<-EOF
|
|
|
|
|
|
|
|
Combined firmware and bootloader are now at ${HEX_FILE_WITH_BOOTLOADER_PATH}
|
|
|
|
Make sure you have the bootloader version you expect.
|
|
|
|
|
|
|
|
And TEST THIS ON REAL HARDWARE BEFORE YOU GIVE IT TO ANYONE
|
|
|
|
|
|
|
|
EOF
|
|
|
|
}
|
|
|
|
|
|
|
|
build() {
|
|
|
|
compile "$@"
|
|
|
|
size "$@"
|
|
|
|
}
|
|
|
|
|
|
|
|
prepare_ccache() {
|
|
|
|
find_sketch
|
|
|
|
build_paths
|
|
|
|
enable_ccache
|
|
|
|
}
|
|
|
|
compile() {
|
|
|
|
find_sketch
|
|
|
|
set_executable_paths
|
|
|
|
build_version
|
|
|
|
build_paths
|
|
|
|
build_filenames
|
|
|
|
# If the hex file is older than the sketch file, or the hex file does not exist
|
|
|
|
# then rebuild. This is not as correct as letting make check our dependencies
|
|
|
|
# But it's less broken for most user use cases
|
|
|
|
# TODO(anyone): Make this suck less
|
|
|
|
if [ "${HEX_FILE_PATH}" -ot "${SKETCH_FILE_PATH}" ]; then
|
|
|
|
do_compile "$@"
|
|
|
|
else
|
|
|
|
echo "${HEX_FILE_PATH} did not need to be rebuilt"
|
|
|
|
fi
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
set_executable_paths() {
|
|
|
|
######
|
|
|
|
###### Executable paths
|
|
|
|
######
|
|
|
|
|
|
|
|
# Allow the compiler path to be empty for virtual builds
|
|
|
|
# should use compiler.path instead of appending bin, but we don't have substitution het
|
|
|
|
: "${COMPILER_PATH=$(get_arduino_pref 'runtime.tools.avr-gcc.path')/bin}"
|
|
|
|
|
|
|
|
COMPILER_SUFFIX=""
|
|
|
|
|
|
|
|
C_COMPILER_BASENAME=$(basename "${CC:-gcc}")
|
|
|
|
CXX_COMPILER_BASENAME=$(basename "${CXX:-g++}")
|
|
|
|
AR_BASENAME=$(basename "${AR:-ar}")
|
|
|
|
|
|
|
|
# Allow the compiler prefix to be empty for virtual builds
|
|
|
|
COMPILER_PREFIX="${COMPILER_PREFIX-avr-}"
|
|
|
|
: "${AVR_SIZE:=${COMPILER_PATH}/${COMPILER_PREFIX}size}"
|
|
|
|
: "${AVR_OBJDUMP:=${COMPILER_PATH}/${COMPILER_PREFIX}objdump}"
|
|
|
|
: "${AVR_OBJCOPY:=${COMPILER_PATH}/${COMPILER_PREFIX}objcopy}"
|
|
|
|
: "${AVR_NM:=${COMPILER_PATH}/${COMPILER_PREFIX}nm}"
|
|
|
|
: "${AVR_AR:=${COMPILER_PATH}/${COMPILER_PREFIX}ar}"
|
|
|
|
}
|
|
|
|
|
|
|
|
do_compile() {
|
|
|
|
prepare_ccache
|
|
|
|
|
|
|
|
install -d "${OUTPUT_PATH}"
|
|
|
|
|
|
|
|
echo "Building ${SKETCH_FILE_PATH}"
|
|
|
|
|
|
|
|
# This is defined in the (optional) user config.
|
|
|
|
# shellcheck disable=SC2154
|
|
|
|
${compile_HOOKS}
|
|
|
|
|
|
|
|
SAVED_BOARD="${BOARD}"
|
|
|
|
SAVED_FQBN="${FQBN}"
|
|
|
|
if [ -e "${SKETCH_DIR}/.kaleidoscope-builder.conf" ]; then
|
|
|
|
# shellcheck disable=SC1090
|
|
|
|
BOARD="$(. "${SKETCH_DIR}"/.kaleidoscope-builder.conf && echo "${BOARD}")"
|
|
|
|
# shellcheck disable=SC1090
|
|
|
|
FQBN="$(. "${SKETCH_DIR}"/.kaleidoscope-builder.conf && echo "${FQBN}")"
|
|
|
|
if [ -n "${BOARD}" ]; then
|
|
|
|
: "${ARCH:=avr}"
|
|
|
|
FQBN="keyboardio:${ARCH}:${BOARD}"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
do_compile_with_cli
|
|
|
|
|
|
|
|
if [ -z "${LIBONLY}" ]; then
|
|
|
|
cp "${BUILD_PATH}/${SKETCH_FILE_NAME}.hex" "${HEX_FILE_PATH}"
|
|
|
|
cp "${BUILD_PATH}/${SKETCH_FILE_NAME}.elf" "${ELF_FILE_PATH}"
|
|
|
|
ln -sf "${OUTPUT_FILE_PREFIX}.hex" "${OUTPUT_PATH}/${SKETCH_BASE_NAME}-latest.hex"
|
|
|
|
ln -sf "${OUTPUT_FILE_PREFIX}.elf" "${OUTPUT_PATH}/${SKETCH_BASE_NAME}-latest.elf"
|
|
|
|
else
|
|
|
|
cp "${BUILD_PATH}/${SKETCH_FILE_NAME}.a" "${LIB_FILE_PATH}"
|
|
|
|
ln -sf "${OUTPUT_FILE_PREFIX}.a" "${OUTPUT_PATH}/${SKETCH_BASE_NAME}-latest.a"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ "${ARDUINO_VERBOSE}" == "--verbose" ]; then
|
|
|
|
echo "Build artifacts can be found in ${BUILD_PATH}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
BOARD="${SAVED_BOARD}"
|
|
|
|
FQBN="${SAVED_FQBN}"
|
|
|
|
}
|
|
|
|
|
|
|
|
get_arduino_pref() {
|
|
|
|
pref=$1
|
|
|
|
# Strip the preference name. And then strip leading and trailing quotations
|
|
|
|
MESSAGE=$(dump_arduino_prefs | grep --max-count=1 "${pref}=" | sed -e s/^.*"${pref}"=// -e 's/^"//' -e 's/"$//')
|
|
|
|
echo "$MESSAGE"
|
|
|
|
}
|
|
|
|
|
|
|
|
dump_arduino_prefs() {
|
|
|
|
if [ "x${_ARDUINO_PREFS}x" == "xx" ]; then
|
|
|
|
_ARDUINO_PREFS=$(run_arduino_cli --fqbn "${FQBN}" compile --show-properties "${SKETCH_FILE_PATH}")
|
|
|
|
fi
|
|
|
|
echo "$_ARDUINO_PREFS"
|
|
|
|
}
|
|
|
|
|
|
|
|
do_compile_with_cli() {
|
|
|
|
#-build-cache "${CORE_CACHE_PATH}" \
|
|
|
|
|
|
|
|
if [ $CCACHE_ENABLED ]; then
|
|
|
|
COMPILER_PATH_PROP="${CCACHE_WRAPPER_PATH}/"
|
|
|
|
else
|
|
|
|
COMPILER_PATH_PROP="${COMPILER_PATH}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
_CMD_CXX="${CXX:-${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}${COMPILER_SUFFIX}}"
|
|
|
|
_CMD_CC="${CC:-${COMPILER_PREFIX}${C_COMPILER_BASENAME}${COMPILER_SUFFIX}}"
|
|
|
|
_CMD_AR="${AR:-${COMPILER_PREFIX}${AR_BASENAME}${COMPILER_SUFFIX}}"
|
|
|
|
run_arduino_cli compile \
|
|
|
|
--fqbn "${FQBN}" \
|
|
|
|
--libraries "${KALEIDOSCOPE_DIR}/.." \
|
|
|
|
--build-path "${BUILD_PATH}" \
|
|
|
|
--output-dir "${OUTPUT_PATH}" \
|
|
|
|
--build-properties "compiler.path=${COMPILER_PATH_PROP}" \
|
|
|
|
--build-properties "compiler.c.cmd=${_CMD_CC}" \
|
|
|
|
--build-properties "compiler.cpp.cmd=${_CMD_CXX}" \
|
|
|
|
--build-properties "compiler.ar.cmd=${_CMD_AR}" \
|
|
|
|
--build-properties "compiler.c.elf.cmd=${_CMD_CXX}" \
|
|
|
|
--build-properties "compiler.cpp.extra_flags=${LOCAL_CFLAGS}" \
|
|
|
|
--warnings all \
|
|
|
|
"${SKETCH_FILE_PATH}"
|
|
|
|
}
|
|
|
|
|
|
|
|
find_all_sketches() {
|
|
|
|
for sketch_name in ./*.ino \
|
|
|
|
$([ -d examples ] && find examples -name '*.ino') \
|
|
|
|
src/*.ino; do
|
|
|
|
if [ -d "$(dirname "${sketch_name}")" ] || [ -f "${sketch_name}" ]; then
|
|
|
|
p="$(basename "${sketch_name}" .ino)"
|
|
|
|
if [ "${p}" != '*' ]; then
|
|
|
|
case "${sketch_name}" in
|
|
|
|
examples/*/${p}/${p}.ino)
|
|
|
|
echo "${sketch_name}" | sed -e "s,examples/,," | sed -e "s,/${p}\\.ino,,"
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
echo "${p}"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done | sort
|
|
|
|
}
|
|
|
|
|
|
|
|
build_all() {
|
|
|
|
plugins="$(find_all_sketches)"
|
|
|
|
|
|
|
|
for sketch in ${plugins}; do
|
|
|
|
export SKETCH="${sketch}"
|
|
|
|
$0 "${sketch}" build
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
size() {
|
|
|
|
compile
|
|
|
|
|
|
|
|
: "${AVR_SIZE_FLAGS:=-C --mcu=$(get_arduino_pref 'build.mcu')}"
|
|
|
|
echo "- Size: ${ELF_FILE_PATH}"
|
|
|
|
# shellcheck disable=SC2086
|
|
|
|
firmware_size "${AVR_SIZE}" ${AVR_SIZE_FLAGS} "${ELF_FILE_PATH}"
|
|
|
|
echo
|
|
|
|
}
|
|
|
|
|
|
|
|
size_map() {
|
|
|
|
compile
|
|
|
|
|
|
|
|
"${AVR_NM}" --size-sort -C -r -l -t decimal "${ELF_FILE_PATH}"
|
|
|
|
}
|
|
|
|
|
|
|
|
disassemble() {
|
|
|
|
compile
|
|
|
|
|
|
|
|
"${AVR_OBJDUMP}" -C -d "${ELF_FILE_PATH}"
|
|
|
|
}
|
|
|
|
|
|
|
|
decompile() {
|
|
|
|
disassemble
|
|
|
|
}
|
|
|
|
|
|
|
|
clean() {
|
|
|
|
find_sketch
|
|
|
|
build_paths
|
|
|
|
if [ -d "$OUTPUT_PATH" ]; then
|
|
|
|
rm -rf -- "${OUTPUT_PATH}"
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
find_bootloader_ports() {
|
|
|
|
if [ -n "${DEVICE_PORT_BOOTLOADER}" ]; then
|
|
|
|
echo "DEVICE_PORT_BOOTLOADER=\"${DEVICE_PORT_BOOTLOADER}\" predefined."
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
find_device_vid_pid
|
|
|
|
: "${BOOTLOADER_VID:=${VID}}"
|
|
|
|
if [ "${uname_S}" = "Darwin" ]; then
|
|
|
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-macos"
|
|
|
|
DEVICE_PORT_BOOTLOADER="$(perl ${DEVICE_PORT_PROBER} ${BOOTLOADER_VID} ${BOOTLOADER_PID})"
|
|
|
|
elif [ "${uname_O}" = "Cygwin" ]; then
|
|
|
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-windows.ps1"
|
|
|
|
DEVICE_PORT_BOOTLOADER="$(powershell -noprofile -executionpolicy bypass ${DEVICE_PORT_PROBER} ${BOOTLOADER_VID} ${BOOTLOADER_PID} -Format COM)"
|
|
|
|
elif [ "${uname_S}" = "FreeBSD" ]; then
|
|
|
|
DEVICE_PORT_PROBER="${KALEIDOSCPE_BIN_DIR}/find-device-port-freebsd"
|
|
|
|
DEVICE_PORT_BOOTLOADER="$(perl ${DEVICE_PORT_PROBER})"
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-linux-udev"
|
|
|
|
DEVICE_PORT_BOOTLOADER="$(perl ${DEVICE_PORT_PROBER} ${BOOTLOADER_VID} ${BOOTLOADER_PID})"
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
find_device_port() {
|
|
|
|
if [ -n "${DEVICE_PORT}" ]; then
|
|
|
|
echo "DEVICE_PORT=\"${DEVICE_PORT}\" predefined."
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
find_device_vid_pid
|
|
|
|
if [ "${uname_S}" = "Darwin" ]; then
|
|
|
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-macos"
|
|
|
|
DEVICE_PORT="$(perl ${DEVICE_PORT_PROBER} ${VID} ${SKETCH_PID})"
|
|
|
|
elif [ "${uname_O}" = "Cygwin" ]; then
|
|
|
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-windows.ps1"
|
|
|
|
DEVICE_PORT="$(powershell -noprofile -executionpolicy bypass ${DEVICE_PORT_PROBER} ${VID} ${SKETCH_PID} -Format Cygwin)"
|
|
|
|
DEVICE_COM_PORT="$(powershell -noprofile -executionpolicy bypass ${DEVICE_PORT_PROBER} ${VID} ${SKETCH_PID} -Format COM)"
|
|
|
|
elif [ "${uname_S}" = "FreeBSD" ]; then
|
|
|
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-freebsd"
|
|
|
|
DEVICE_PORT="$(perl ${DEVICE_PORT_PROBER})"
|
|
|
|
else
|
|
|
|
DEVICE_PORT_PROBER="${KALEIDOSCOPE_BIN_DIR}/find-device-port-linux-udev"
|
|
|
|
DEVICE_PORT="$(perl ${DEVICE_PORT_PROBER} ${VID} ${SKETCH_PID})"
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
usage() {
|
|
|
|
cat <<-EOF
|
|
|
|
Usage: $0 SKETCH commands...
|
|
|
|
|
|
|
|
Runs all of the commands in the context of the Sketch.
|
|
|
|
|
|
|
|
Available commands:
|
|
|
|
|
|
|
|
help
|
|
|
|
This help screen.
|
|
|
|
|
|
|
|
compile
|
|
|
|
Compiles the sketch.
|
|
|
|
|
|
|
|
size
|
|
|
|
Reports the size of the compiled sketch.
|
|
|
|
|
|
|
|
build
|
|
|
|
Runs compile and report-size.
|
|
|
|
|
|
|
|
clean
|
|
|
|
Cleans up the output directory.
|
|
|
|
|
|
|
|
size-map
|
|
|
|
Displays the size map for the sketch.
|
|
|
|
|
|
|
|
disassemble
|
|
|
|
Decompile the sketch.
|
|
|
|
|
|
|
|
reset-device
|
|
|
|
Reset the device.
|
|
|
|
|
|
|
|
flash
|
|
|
|
Flashes the firmware using avrdude.
|
|
|
|
|
|
|
|
EOF
|
|
|
|
}
|
|
|
|
|
|
|
|
help() {
|
|
|
|
usage
|
|
|
|
}
|
|
|
|
|
|
|
|
if [ $# -lt 1 ]; then
|
|
|
|
usage
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
# Temporary migration for old makefiles
|
|
|
|
# I'm not thrilled about how we default to system Arduino dirs.
|
|
|
|
if [ -n "${BOARD_HARDWARE_PATH}" ]; then
|
|
|
|
ARDUINO_DIRECTORIES_USER="${BOARD_HARDWARE_PATH}/../"
|
|
|
|
fi
|
|
|
|
|
|
|
|
: "${KALEIDOSCOPE_DIR:=$(
|
|
|
|
cd "$(dirname "$0")"/..
|
|
|
|
pwd
|
|
|
|
)}"
|
|
|
|
# shellcheck disable=SC2034
|
|
|
|
: "${KALEIDOSCOPE_BIN_DIR:=${KALEIDOSCOPE_DIR}/bin/}"
|
|
|
|
|
|
|
|
identify_os
|
|
|
|
read_conf_files
|
|
|
|
configure_arduino_cli_env
|
|
|
|
|
|
|
|
# shellcheck disable=SC1090
|
|
|
|
|
|
|
|
if [ -n "${VERBOSE}" ] && [[ "${VERBOSE}" -gt 0 ]]; then
|
|
|
|
ARDUINO_VERBOSE="--verbose"
|
|
|
|
else
|
|
|
|
ARDUINO_VERBOSE="--quiet"
|
|
|
|
fi
|
|
|
|
|
|
|
|
: "${BOARD:=model01}"
|
|
|
|
|
|
|
|
if [[ -z "${ARCH}" && -n "${FQBN}" ]]; then
|
|
|
|
ARCH=$(echo "${FQBN}" | sed -n -e 's/^[^:]\+:\([^:]\+\).*/\1/p')
|
|
|
|
fi
|
|
|
|
|
|
|
|
: "${ARCH:=avr}"
|
|
|
|
: "${FQBN:=keyboardio:${ARCH}:${BOARD}}"
|
|
|
|
|
|
|
|
if [ "${ARCH}" = "virtual" ]; then
|
|
|
|
adjust_for_virtual_build
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ "${uname_O}" = "Cygwin" ]; then
|
|
|
|
adjust_for_cygwin
|
|
|
|
fi
|
|
|
|
|
|
|
|
## Parse the command-line
|
|
|
|
## - anything that has a =, is an env var
|
|
|
|
## - from the remaining stuff, the first one is the Library/Sketch
|
|
|
|
## - everything else are commands
|
|
|
|
##
|
|
|
|
## - if there is only one argument, that's a command
|
|
|
|
|
|
|
|
cmds=""
|
|
|
|
|
|
|
|
## Export vars
|
|
|
|
for i in $(seq 1 $#); do
|
|
|
|
v="$1"
|
|
|
|
shift
|
|
|
|
|
|
|
|
case "${v}" in
|
|
|
|
*=*)
|
|
|
|
# Exporting an expansion is *precisely* what we want here.
|
|
|
|
# shellcheck disable=SC2086,SC2163
|
|
|
|
export ${v}
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
cmds="${cmds} ${v}"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
|
|
|
# Word splitting is desired here.
|
|
|
|
# shellcheck disable=SC2086
|
|
|
|
set -- ${cmds}
|
|
|
|
|
|
|
|
if [ $# -eq 1 ]; then
|
|
|
|
cmd="$(echo "$1" | tr '-' '_')"
|
|
|
|
${cmd}
|
|
|
|
exit $?
|
|
|
|
fi
|
|
|
|
|
|
|
|
SKETCH="$1"
|
|
|
|
shift
|
|
|
|
|
|
|
|
cmds=""
|
|
|
|
|
|
|
|
# shellcheck disable=2034
|
|
|
|
for i in $(seq 1 $#); do
|
|
|
|
cmds="${cmds} $(echo "$1" | tr '-' '_')"
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
|
|
|
for cmd in ${cmds}; do
|
|
|
|
${cmd}
|
|
|
|
done
|