Initial commit

This commit is contained in:
2022-10-09 17:25:45 +03:00
commit da10f7c5cd
60 changed files with 6255 additions and 0 deletions

66
tools/bashlib.sh Normal file
View File

@ -0,0 +1,66 @@
#!/bin/false
# Writes a message to stderr.
# Parameters:
# $@ - the message to display
function error() {
echo >&2 "`basename "$0"`: $@"
}
# Writes a message to stderr and exits with code 1.
# Parameters:
# $@ - the message to display
function fail() {
error "$@"
exit 1;
}
# Ensures that a variable with name $1 has a valid executable. If it does not,
# this function attempts to find an executable with a name suggested in $2...$n.
# In either way, if the variable does not end up naming an executable, fail() is
# called.
# Parameters:
# $1 - name of the variable to check and modify
# $2...$n - suggested executables (at least one)
# $FAIL_SILENTLY - if set, don't call exit and don't print anything on failure
function find_cmd() {
declare -n target="$1"
if [ -z "${target+x}" ]; then
for candidate in "${@:2}"; do
if command -v "$candidate" >/dev/null; then
target="$candidate"
break
fi
done
fi
if ! command -v "$target" >/dev/null; then
[ -n "${FAIL_SILENTLY+x}" ] && return 1
fail "Command $2 is not available. Check \$PATH or set \$$1."
fi
unset -n target
return 0
}
# Displays the command and then runs it.
# Parameters:
# $@ - the command to run
function echo_and_run() {
echo " > $*"
command "$@"
}
root_dir="$(dirname "$(dirname "$(realpath "${BASH_SOURCE[0]}")")")"
source_dir="$root_dir"
build_dir="$root_dir/build"
tools_dir="$root_dir/tools"
# Load private.sh
private_sh="$tools_dir/private.sh"
if [ -f "$private_sh" ]; then
[ -x "$private_sh" ] \
|| fail 'tools/private.sh exists but it is not executable'
source "$private_sh"
fi

170
tools/build.sh Executable file
View File

@ -0,0 +1,170 @@
#!/bin/bash
usage=\
"Usage: build.sh [OPTIONS...] [TOOL-ARGUMENT...]
Build and run the game.
Options:
--debug make a debug build (default)
--release make a release build
--dont-generate don't generate build instructions; use existing
configuration if building
--dont-build don't build; run existing binaries or generate build
instructions only
--debug-vulkan enable Vulkan validation layers from LunarG
-R, --run run the game after building
--memcheck[=ARGS] run the game using valgrind's memcheck dynamic memory
analysis tool. Implies -R. ARGS is the ;-separated
list of arguments to pass to valgrind/memcheck.
-h, --help display this help and exit
Environment variables:
PARALLELISM threads to use, default is 1
CMAKE cmake executable
VALGRIND valgrind executable
See also: tools/cppcheck/use-cppcheck.sh --help
tools/clang-format/use-clang-format.sh --help
tools/setup.sh --help"
rsrc="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
source "$rsrc/bashlib.sh"
# Parse arguments
build_type=Debug
do_generate=true
do_build=true
run_type=Normal
do_run=''
debug_vulkan=''
memcheck_args=()
for arg in "$@"; do
if [ $is_cmake_arg ]; then
cmake_args+=("$arg")
else
case "$arg" in
-h | --help )
echo "$usage"
exit
;;
--debug )
build_type=Debug
;;
--release )
build_type=Release
;;
--debug-vulkan )
debug_vulkan=true
;;
-R | --run )
do_run=true
;;
--memcheck )
do_run=true
run_type=memcheck
;;
--memcheck=* )
do_run=true
run_type=memcheck
readarray -t -d ';' new_memcheck_args <<<"${arg#*=};"
unset new_memcheck_args[-1]
memcheck_args+=("${new_memcheck_args[@]}")
unset new_memcheck_args
;;
--dont-generate )
do_generate=''
;;
--dont-build )
do_build=''
;;
* )
fail "Unknown option '$arg'"
;;
esac
fi
done
if [ -z "$do_build" -a -z "$do_generate" -a ${#cmake_args[@]} != 0 ]; then
fail "CMake arguments are set, but no build is requested. Aborting"
fi
if [ -z "$do_build" -a -z "$do_generate" -a -z "$do_run" ]; then
fail "Nothing to do"
fi
# Generate build files
find_cmd CMAKE cmake
if [ $do_generate ]; then
echo_and_run "$CMAKE" \
-B "$build_dir" \
-S "$source_dir" \
-DCMAKE_BUILD_TYPE=$build_type \
-DVULKAN_ERROR_CHECKING=`[ $debug_vulkan ] && echo ON || echo OFF` \
"${cmake_args[@]}" \
|| fail "Could not generate build files"
fi
# Build
find_cmd CMAKE cmake
if [ $do_build ]; then
options=()
[ -n "${PARALLELISM+x}" ] && options+=(-j "$PARALLELISM")
echo_and_run "$CMAKE" \
--build "$build_dir" \
"${options[@]}" \
|| fail "Build failed"
unset options
fi
# Run
if [ $do_run ]; then
run_command=()
if [ $run_type == memcheck ]; then
find_cmd VALGRIND valgrind
run_command+=(
"$VALGRIND"
--tool=memcheck
--suppressions="$tools_dir"/memcheck/suppressions.supp
"${memcheck_args[@]}"
--
)
fi
run_command+=(
"$build_dir/progressia"
)
run_dir="$root_dir/run"
mkdir -p "$run_dir"
(
cd "$run_dir"
echo_and_run "${run_command[@]}"
echo "Process exited with code $?"
)
fi

View File

@ -0,0 +1,4 @@
BasedOnStyle: LLVM
# Use larger indentation
IndentWidth: 4

View File

@ -0,0 +1,104 @@
#!/bin/bash
usage=\
"Usage: use-clang-format.sh git
or: use-clang-format.sh files FILES...
or: use-clang-format.sh raw ARGUMENTS...
In the 1st form, format all files that have changed since last git commit.
In the 2nd form, format all FILES, treating directories recursively.
In the 3rd form, run \`clang-format --style=<style> ARGUMENTS...\`.
Environment variables:
CLANG_FORMAT clang-format executable
CLANG_FORMAT_DIFF clang-format-diff script"
rsrc="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
source "$rsrc/../bashlib.sh"
case "$1" in
git )
find_cmd CLANG_FORMAT_DIFF \
clang-format-diff-13 \
clang-format-diff \
clang-format-diff.py
;;
files | raw )
find_cmd CLANG_FORMAT \
clang-format-13 \
clang-format
;;
-h | --help | '' )
echo "$usage"
exit
;;
* )
fail "Unknown option '$1'"
;;
esac
# Generate style argument
style=''
while IFS='' read line; do
[ -z "$line" ] && continue
[ "${line:0:1}" = '#' ] && continue
[ -n "$style" ] && style+=', '
style+="$line"
done < "$rsrc/clang-format.yml"
style="{$style}" # Not typo
case "$1" in
git )
unstaged_changes="`git diff --name-only`"
if [ -n "$unstaged_changes" ]; then
fail "Refusing to operate in git repository with unstaged changes:
$unstaged_changes"
fi
git diff -U0 --no-color --relative HEAD \
'*.cpp' \
'*.h' \
'*.inl' \
| command "$CLANG_FORMAT_DIFF" -p1 -style="$style" -i --verbose
exit_code="$?"
git add "$root_dir"
exit "$exit_code"
;;
raw )
command "$CLANG_FORMAT" -style="$style" "$@"
;;
files )
files=()
for input in "${@:2}"; do
if [ -d "$input" ]; then
readarray -d '' current_files < <(
find "$input" \
\( -name '*.cpp' -o -name '*.h' -o -name '*.inl' \) \
-type f \
-print0 \
)
[ "${#current_files[@]}" -eq 0 ] \
&& fail "No suitable files found in directory $input"
files+=("${current_files[@]}")
else
case "$input" in
*.cpp | *.h | *.inl )
files+=("$input")
;;
* )
error "Refusing to format file '$input': `
`only .cpp, .h and .inl supported"
;;
esac
fi
done
[ "${#files[@]}" -eq 0 ] && fail "No files to format"
command "$CLANG_FORMAT" -style="$style" -i --verbose "${files[@]}"
;;
esac

56
tools/cmake/embed.cmake Normal file
View File

@ -0,0 +1,56 @@
# Global variables. Yikes. FIXME
set(tools ${PROJECT_SOURCE_DIR}/tools)
set(generated ${PROJECT_BINARY_DIR}/generated)
set(assets_to_embed "")
set(assets_to_embed_args "")
file(MAKE_DIRECTORY ${generated})
find_package(Vulkan COMPONENTS glslc REQUIRED)
find_program(glslc_executable NAMES glslc HINTS Vulkan::glslc)
set(shaders ${generated}/shaders)
file(MAKE_DIRECTORY ${shaders})
# Shedules compilation of shaders
# Adapted from https://stackoverflow.com/a/60472877/4463352
macro(compile_shader)
foreach(source ${ARGV})
get_filename_component(source_basename ${source} NAME)
set(tmp "${shaders}/${source_basename}.spv")
add_custom_command(
OUTPUT ${tmp}
DEPENDS ${source}
COMMAND ${glslc_executable}
-o ${tmp}
${CMAKE_CURRENT_SOURCE_DIR}/${source}
COMMENT "Compiling shader ${source}"
)
list(APPEND assets_to_embed_args "${tmp};as;${source_basename}.spv")
list(APPEND assets_to_embed "${tmp}")
unset(tmp)
unset(source_basename)
endforeach()
endmacro()
compile_shader(
desktop/graphics/shaders/shader.frag
desktop/graphics/shaders/shader.vert
)
# Generate embed files
add_custom_command(
OUTPUT ${generated}/embedded_resources.cpp
${generated}/embedded_resources.h
COMMAND ${tools}/embed/embed.py
--cpp ${generated}/embedded_resources.cpp
--header ${generated}/embedded_resources.h
--
${assets_to_embed_args}
DEPENDS "${assets_to_embed}"
${tools}/embed/embed.py
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Embedding assets"
)

View File

@ -0,0 +1,28 @@
# CppCheck command line arguments
# Each line is treated as one argument, unless it is empty or it starts with #.
#
# Available variables:
# ${CMAKE_SOURCE_DIR} project root
# ${CMAKE_BINARY_DIR} CMake build directory
--enable=warning,style,information
#--enable=unusedFunction # Unused functions are often OK since they are intended
# # to be used later
#--enable=missingInclude # Very prone to false positives; system-dependent
--inconclusive
# SUPPRESSIONS
# Warnings that are suppressed on a case-by-case basis should be suppressed
# using inline suppressions.
# Warnings that were decided to be generally inapplicable should be suppressed
# using suppressions.txt.
# Warnings that result from the way cppcheck is invoked should be suppressed
# using this file.
--inline-suppr
--suppressions-list=${CMAKE_SOURCE_DIR}/tools/cppcheck/suppressions.txt
# N.B.: this path is also mentioned in use scripts
--cppcheck-build-dir=${CMAKE_BINARY_DIR}/cppcheck
--error-exitcode=2

View File

@ -0,0 +1,15 @@
# CppCheck global suppressions
# Do not use this file for suppressions that could easily be declared inline.
# Allow the use of implicit constructors.
noExplicitConstructor:*
# In most cases using STL algorithm functions causes unnecessary code bloat.
useStlAlgorithm:*
# cppcheck trips on #include <embedded_resources.h> and there's no way to
# suppress that exlusively
missingInclude:*
# Shut up. Just shut up.
unmatchedSuppression:*

65
tools/cppcheck/use-cppcheck.sh Executable file
View File

@ -0,0 +1,65 @@
#!/bin/bash
usage=\
"Usage: use-cppcheck.sh
Run cppcheck with correct options.
Environment variables:
PARALLELISM threads to use, default is 1
CPPCHECK cppcheck executable
CMAKE cmake executable"
rsrc="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
source "$rsrc/../bashlib.sh"
find_cmd CPPCHECK cppcheck
find_cmd CMAKE cmake
case "$1" in
-h | --help )
echo "$usage"
exit
;;
esac
# Generate compile database for CppCheck
command "$CMAKE" \
-B "$build_dir" \
-S "$source_dir" \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
compile_database="$build_dir/compile_commands.json"
mkdir -p "$build_dir/cppcheck"
options=()
while IFS='' read -r line; do
[ -z "$line" ] && continue
[ "${line:0:1}" = '#' ] && continue
option="$(
CMAKE_SOURCE_DIR="$source_dir" \
CMAKE_BINARY_DIR="$build_dir" \
envsubst <<<"$line"
)"
options+=("$option")
done < "$tools_dir/cppcheck/options.txt"
[ -n "${PARALLELISM+x}" ] && options+=(-j "$PARALLELISM")
errors="`
echo_and_run "$CPPCHECK" \
--project="$compile_database" \
-D__CPPCHECK__ \
"${options[@]}" \
2>&1 >/dev/fd/0 # Store stderr into variable, pass stdout to our stdout
`"
exit_code="$?"
if [ "$exit_code" -eq 2 ]; then
less - <<<"$errors"
exit "$exit_code"
fi

298
tools/embed/embed.py Executable file
View File

@ -0,0 +1,298 @@
#!/usr/bin/env python3
usage = \
'''Usage: embed.py --cpp OUT_CPP --header OUT_H [--] [INPUT as PATH]...
Generate C++ source code that includes binary contents of INPUT files.
Each file in INPUT is stored as a resource: a static array of unsigned char.
It is identified by a PATH. If PATH is "auto", resource path is the path of
the file relative to this script's working directory with forward slash '/'
as separator.
Use -- to make sure the following one INPUT is not interpreted as an option.
This script generates two files:
OUT_CPP is a C++ implementation file that includes the contents of INPUT.
OUT_H is a C++ header file that declares several methods of access to the data
in OUT_CPP. It should be located in the same directory as OUT_H at compile
time.
OUT_H declares the following symbols:
namespace __embedded_resources {
struct EmbeddedResource {
const unsigned char *data;
std::size_t length;
};
EmbeddedResource getEmbeddedResource(const char *path);
}
getEmbeddedResource(const char *path) returns an EmbeddedResource structure that
contains the pointer to the beginning of the requested resource and its
length, or {nullptr, 0} if the resource does not exist.'''
import sys
import os
import re
from types import SimpleNamespace
from json import dumps as json_dumps
def fail(*args):
my_name = os.path.basename(sys.argv[0])
print(my_name + ':', *args, file=sys.stderr)
sys.exit(1)
def main():
# Parse arguments
out_cpp_path = None
out_h_path = None
inputs = []
argi = 1
considerOptions = True
while argi < len(sys.argv):
arg = sys.argv[argi]
if considerOptions and arg.startswith('--cpp'):
if arg == '--cpp':
argi += 1
if argi == len(sys.argv):
fail('Missing argument for --cpp')
out_cpp_path = sys.argv[argi]
elif arg.startswith('--impl='):
out_cpp_path = arg.removeprefix('--cpp=')
else:
fail(f"Unknown option '{arg}'")
elif considerOptions and arg.startswith('--header'):
if arg == '--header':
argi += 1
if argi == len(sys.argv):
fail('Missing argument for --header')
out_h_path = sys.argv[argi]
elif arg.startswith('--header='):
out_h_path = arg.removeprefix('--header=')
else:
fail(f"Unknown option '{arg}'")
elif considerOptions and (arg == '-h' or arg == '--help'):
sys.exit(0)
elif considerOptions and arg == '--':
considerOptions = False
elif considerOptions and arg.startswith('-'):
fail(f"Unknown option '{arg}'")
else:
if argi + 2 >= len(sys.argv):
fail(f'Invalid input declaration {sys.argv[argi:]}: '
'expected "INPUT as PATH"')
if sys.argv[argi + 1] != 'as':
fail(f'Invalid input declaration {sys.argv[argi:argi+3]}: '
'expected "INPUT as PATH"')
the_input = arg
argi += 2
name = sys.argv[argi]
if name == 'auto':
name = os.path.relpath(the_input).replace(os.sep, '/')
inputs.append((the_input, name))
argi += 1
if out_cpp_path == None:
fail('--impl not set')
if out_h_path == None:
fail('--header not set')
if len(inputs) == 0:
fail('No inputs')
generate_impl(out_cpp_path, out_h_path, inputs)
generate_header(out_h_path)
def generate_impl(out_cpp_path, out_h_path, inputs):
try:
with open(out_cpp_path, 'w', encoding="utf-8") as output:
output.write(impl.start %
{'header_name': os.path.basename(out_h_path)})
variables = {}
# Open each input
for number, (input_path, resource_path) in enumerate(inputs):
variable_name = make_variable_name(resource_path, number)
if resource_path in variables:
fail('Inputs resolve to duplicate resource paths: ' +
resource_path)
variables[resource_path] = variable_name
try:
with open(input_path, 'rb') as input_file:
write_bytes(output, input_file, variable_name)
if number == len(inputs) - 1:
output.write(";\n")
else:
output.write(",\n")
except FileNotFoundError as e:
fail(f"Input file '{input_path}' does not exist")
except (PermissionError, OSError) as e:
fail(f"Could not read input '{input_path}': {e}")
output.write(impl.mid)
# Add EmbeddedResources to lookup table
for number, (resource, variable) in enumerate(variables.items()):
output.write(impl.mapping % {
'resource_path_quoted': json_dumps(resource),
'variable_name': variable})
if number == len(variables) - 1:
output.write("\n")
else:
output.write(",\n")
output.write(impl.end)
except (FileNotFoundError, PermissionError, OSError) as e:
fail(f"Could not write to '{out_cpp_path}': {e}")
def make_variable_name(resource_path, number):
max_variable_name_length = 255 # very conservative
max_path_length = max_variable_name_length - \
len(impl.variable_name.format(number, ''))
return impl.variable_name % (number,
re.sub(r'\W', '_', resource_path[-max_path_length:]).upper())
def write_bytes(out_file, in_file, variable_name):
out_file.write(impl.declar_start % variable_name)
max_line_length = 79
line = impl.declar_mid_prefix
# Process contents in chunks
while True:
chunk = in_file.read1(-1)
if len(chunk) == 0:
break
for byte in chunk:
byte_str = str(byte)
if len(line) + 1 + len(byte_str) > max_line_length:
out_file.write(line + '\n')
line = impl.declar_mid_prefix
line += byte_str + ','
out_file.write(line[:-1] + '\n')
out_file.write(impl.declar_end)
def generate_header(out_h_path):
try:
with open(out_h_path, 'w', encoding="utf-8") as output:
output.write(header)
except (FileNotFoundError, PermissionError, OSError) as e:
fail(f"Could not write to '{out_h_path}': {e}")
# Templates
impl = SimpleNamespace(
start=\
'''/*
* This file is autogenerated by tools/embed/embed.py. Do not edit directly.
* Add this file as a compilation unit.
*/
#include <unordered_map>
#include <string>
#include "%(header_name)s"
namespace {
const unsigned char
''',
mid=\
'''
std::unordered_map<std::string,
__embedded_resources::EmbeddedResource>
EMBEDDED_RESOURCES =
{
''',
end=\
''' };
}
namespace __embedded_resources {
EmbeddedResource getEmbeddedResource(const std::string &path) {
auto result = EMBEDDED_RESOURCES.find(path);
if (result == EMBEDDED_RESOURCES.end()) {
return EmbeddedResource{nullptr, 0};
}
return result->second;
}
}
''',
mapping=\
''' {%(resource_path_quoted)s, {
%(variable_name)s,
sizeof(%(variable_name)s)
}}''',
declar_start= " %s[] = {\n",
declar_mid_prefix= ' ',
declar_end= ' }',
variable_name='EMBED_%s_%s'
)
header = '''/*
* This file is autogenerated by tools/embed/embed.py. Do not edit directly.
* Include this header as necessary.
*/
#pragma once
#include <string>
namespace __embedded_resources {
struct EmbeddedResource {
const unsigned char *data;
std::size_t length;
};
EmbeddedResource getEmbeddedResource(const std::string &path);
}
'''
if __name__ == '__main__':
main()

51
tools/git/hook_pre_commit.sh Executable file
View File

@ -0,0 +1,51 @@
#!/bin/bash
me="$(realpath "${BASH_SOURCE[0]}")"
if [ "$(basename "$me")" = 'pre-commit' ]; then
# i write good shell scripts - Javapony 2022-10-07
root_dir="$(realpath "$(dirname "$me")/../../")"
hook_source="$root_dir/tools/git/hook_pre_commit.sh"
if [ "$hook_source" -nt "$me" ]; then
if [ -n "${ALREADY_UPDATED+x}" ]; then
echo >&2 "git pre-commit hook: Attempted recursive hook update. `
`Something is very wrong."
exit 1
fi
echo ''
echo "===== tools/git/hook_pre_commit.sh updated; `
`replacing pre-commit hook ====="
echo ''
cp "$hook_source" "$me" &&
chmod +x "$me" \
|| fail 'Update failed'
ALREADY_UPDATED=true "$me"
exit $?
fi
source "$root_dir/tools/bashlib.sh"
else
rsrc="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
source "$rsrc/../bashlib.sh"
fi
unstaged_changes="`git diff --name-only`"
if [ -n "$unstaged_changes" ]; then
fail "Please stage all stash all unstaged changes in the following files:
$unstaged_changes"
fi
echo_and_run "$tools_dir/cppcheck/use-cppcheck.sh" \
|| fail "Cppcheck has generated warnings, aborting commit"
echo_and_run "$tools_dir/clang-format/use-clang-format.sh" git \
|| fail "clang-format has failed, aborting commit"
echo_and_run "$tools_dir/build.sh" --dont-generate \
|| fail "Could not build project, aborting commit"
echo 'All checks passed'

View File

@ -0,0 +1,28 @@
{
Known X library leak (1)
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
obj:/usr/lib/x86_64-linux-gnu/libxcb.so.1.1.0
...
fun:vkEnumeratePhysicalDevices
}
{
Known X library leak (2)
Memcheck:Leak
match-leak-kinds: definite
fun:calloc
fun:_XimOpenIM
fun:_XimRegisterIMInstantiateCallback
fun:XRegisterIMInstantiateCallback
fun:_glfwPlatformInit
fun:glfwInit
}
{
Ignore errors in DL loading
Memcheck:Addr8
...
fun:decompose_rpath
...
fun:dl_open_worker
}

147
tools/setup.sh Executable file
View File

@ -0,0 +1,147 @@
#!/bin/bash
usage=\
"Usage: setup.sh [--for-development]
Set up the development environment after \`git clone\`
Options:
--for-development perform additional setup only necessary for developers
-h, --help display this help and exit"
rsrc="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
source "$rsrc/bashlib.sh" || {
echo >&2 'Could not load bashlib'
exit 1
}
cd "$root_dir"
# Parse arguments
for_development=''
for arg in "$@"; do
case "$arg" in
-h | --help )
echo "$usage"
exit
;;
--for-development )
for_development=true
;;
* )
fail "Unknown option '$arg'"
;;
esac
done
# Сreate private.sh
if [ ! -e "$private_sh" ]; then
echo '#!/bin/bash
# This file is ignored by git. Use it to configure shell scripts in tools/
# for your development environment.
PARALLELISM=1
#PATH="$PATH:/opt/whatever"
' >"$private_sh" &&
chmod +x "$private_sh" ||
fail "tools/private.sh was not found; could not create it"
echo "Created tools/private.sh"
else
echo "Found and loaded private.sh"
fi
# Check available commands
failed=()
function check_cmd() {
if FAIL_SILENTLY=true find_cmd found "$@"; then
echo "Found command $found"
else
failed+=("command $1")
echo "Could not find command $1"
fi
unset found
}
check_cmd pkg-config
check_cmd cmake
check_cmd python3
check_cmd glslc
if [ $for_development ]; then
check_cmd git
check_cmd cppcheck
check_cmd clang-format-13 clang-format
check_cmd clang-format-diff-13 clang-format-diff clang-format-diff.py
check_cmd valgrind
fi
# Try generating build files
if FAIL_SILENTLY=true find_cmd found_cmake cmake; then
if CMAKE="$found_cmake" "$tools_dir/build.sh" --dont-build; then
echo 'CMake did not encounter any problems'
else
echo 'Could not generate build files; libraries are probably missing'
failed+=('some libraries, probably (see CMake messages for details)')
fi
else
echo 'Skipping CMake test because cmake was not found'
fi
# Display accumulated errors
[ ${#failed[@]} -ne 0 ] &&
fail "Could not find the following required commands or libraries:
`for f in "${failed[@]}"; do echo " $f"; done`
You can resolve these errors in the following ways:
1. Install required software packages. See README for specific instructions.
2. Edit PATH, PKG_CONFIG_PATH or CMAKE_MODULE_PATH environment variables in
tools/private.sh to include your installation directories.
"
# Set executable flags
chmod -v +x tools/build.sh \
tools/embed/embed.py \
|| fail 'Could not make scripts executable'
if [ $for_development ]; then
chmod -v +x tools/clang-format/use-clang-format.sh \
tools/cppcheck/use-cppcheck.sh \
|| fail 'Could not make developer scripts executable'
fi
# Set git hook
if [ $for_development ]; then
mkdir -vp .git/hooks &&
cp -v tools/git/hook_pre_commit.sh .git/hooks/pre-commit &&
chmod -v +x .git/hooks/pre-commit \
|| fail 'Could not setup git pre-commit hook'
fi
echo 'Setup complete'