2023-03-23 12:11:30 +00:00
|
|
|
#!/bin/bash
|
|
|
|
projectPattern="*.uvprojx";
|
|
|
|
|
2023-03-23 14:32:44 +00:00
|
|
|
if [ "$#" -gt 1 ]
|
|
|
|
then
|
|
|
|
1>&2 echo "Error: Invalid number of arguments: $#";
|
|
|
|
fi;
|
|
|
|
|
|
|
|
if [ "$#" -ne 1 ] || [ "$1" == "-h" ] || [ "$1" == "--help" ]
|
|
|
|
then
|
|
|
|
echo "Usage: ${BASH_SOURCE[0]} <path-to-project-or-source-file>";
|
|
|
|
exit;
|
|
|
|
fi;
|
|
|
|
|
2023-04-01 13:02:32 +00:00
|
|
|
function is_truthy() {
|
|
|
|
local value;
|
|
|
|
value="$1";
|
|
|
|
|
2023-04-01 13:10:29 +00:00
|
|
|
[ ! -z "$value" ] &&
|
|
|
|
[ "$value" != "0" ] &&
|
|
|
|
[ "$value" != "false" ] &&
|
|
|
|
[ "$value" != "n" ] &&
|
2023-04-01 13:02:32 +00:00
|
|
|
[ "$value" != "no" ];
|
|
|
|
}
|
2023-03-23 14:32:44 +00:00
|
|
|
|
2023-03-23 12:11:30 +00:00
|
|
|
function handle_status() {
|
|
|
|
if [ $1 -ne 0 ]; then
|
|
|
|
echo "Error: $2 (status code: $1)";
|
|
|
|
exit $1;
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
function regex_escape() {
|
|
|
|
echo "$1" | sed "s/[^\^]/[&]/g; s/\^/\0/g";
|
|
|
|
}
|
|
|
|
|
|
|
|
function normalize_path() {
|
|
|
|
echo "$1" | sed "s/\\\\/\\//g";
|
|
|
|
}
|
|
|
|
|
|
|
|
function getTargetXPath() {
|
|
|
|
index="$1";
|
|
|
|
echo -n "Project/Targets/Target";
|
|
|
|
|
|
|
|
if [ ! -z "$index" ]
|
|
|
|
then
|
|
|
|
echo -n "[$index]";
|
|
|
|
fi;
|
|
|
|
|
|
|
|
echo "";
|
|
|
|
}
|
|
|
|
|
|
|
|
function getFileXPath() {
|
|
|
|
index="$1";
|
|
|
|
echo "$(echo -n "$(getTargetXPath "$index")")/Groups/Group/Files/File/FilePath";
|
|
|
|
}
|
|
|
|
|
|
|
|
function getOptionPath() {
|
|
|
|
index="$1";
|
|
|
|
echo "$(echo -n "$(getTargetXPath "$index")")/TargetOption/TargetCommonOption";
|
|
|
|
}
|
|
|
|
|
|
|
|
function find_files() {
|
|
|
|
local -n files=$1;
|
|
|
|
arguments=("${@:2}");
|
|
|
|
readarray -d '' files < <(find "${arguments[@]}" -print0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
function find_project() {
|
|
|
|
file="$1";
|
|
|
|
currentDir="$(dirname "$file")";
|
|
|
|
find_files projectFiles "$currentDir" -name "$projectPattern";
|
|
|
|
|
|
|
|
while true;
|
|
|
|
do
|
|
|
|
for projectFile in "${projectFiles[@]}"
|
|
|
|
do
|
|
|
|
if containsFile "$file" "$projectFile"
|
|
|
|
then
|
|
|
|
echo "$projectFile";
|
|
|
|
return;
|
|
|
|
fi;
|
|
|
|
done;
|
|
|
|
|
|
|
|
if [ "$currentDir" != "/" ];
|
|
|
|
then
|
|
|
|
currentDir="$(dirname "$currentDir")";
|
|
|
|
find_files projectFiles "$currentDir" -maxdepth 1 -name "$projectPattern";
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
fi;
|
|
|
|
done;
|
|
|
|
}
|
|
|
|
|
|
|
|
function containsFile() {
|
|
|
|
local i;
|
|
|
|
file="$1";
|
|
|
|
projectFile="$2";
|
|
|
|
targetIndex="$3";
|
|
|
|
xpath="$(getFileXPath "$targetIndex")";
|
|
|
|
|
|
|
|
relativePath="$(realpath --relative-to "$(dirname "$projectFile")" "$(dirname "$file")")";
|
|
|
|
filePattern="$(regex_escape "$(basename "$file")")";
|
|
|
|
|
|
|
|
while [ "$relativePath" != "." ];
|
|
|
|
do
|
|
|
|
filePattern="$(regex_escape "$(basename "$relativePath")")"'[/\\\\]'"$filePattern";
|
|
|
|
relativePath="$(dirname "$relativePath")";
|
|
|
|
done;
|
|
|
|
|
|
|
|
fileCount="$(xmlstarlet select --template --copy-of "count($xpath)" "$projectFile")";
|
|
|
|
|
|
|
|
for i in $(seq 1 $fileCount)
|
|
|
|
do
|
|
|
|
currentFileName="$(xmlstarlet select --template --match "($xpath)[$i]" --value-of . "$projectFile")";
|
|
|
|
currentFileName="$(normalize_path "$currentFileName")";
|
|
|
|
currentFileName="$(realpath --relative-to=. -m "$currentFileName")";
|
|
|
|
|
|
|
|
if echo "$currentFileName" | grep "^$filePattern$" > /dev/null
|
|
|
|
then
|
|
|
|
true;
|
|
|
|
return;
|
|
|
|
fi;
|
|
|
|
done;
|
|
|
|
|
|
|
|
false;
|
|
|
|
}
|
|
|
|
|
|
|
|
function chooseTarget() {
|
|
|
|
local i;
|
|
|
|
projectFile="$1";
|
|
|
|
file="$2";
|
|
|
|
targetCandidates=();
|
|
|
|
targetCount="$(xmlstarlet select --template --copy-of "count($(getTargetXPath))" "$projectFile")";
|
|
|
|
|
|
|
|
if [ $targetCount -gt 0 ]
|
|
|
|
then
|
|
|
|
for i in $(seq 1 $targetCount)
|
|
|
|
do
|
|
|
|
if containsFile "$file" "$projectFile" "$i"
|
|
|
|
then
|
|
|
|
targetCandidates+=("$i");
|
|
|
|
fi;
|
|
|
|
done;
|
|
|
|
|
|
|
|
if [ "${#targetCandidates[@]}" = 0 ]
|
|
|
|
then
|
|
|
|
targetCandidates=($(seq 1 "$targetCount"));
|
|
|
|
fi;
|
|
|
|
|
|
|
|
while [ ! "${#targetCandidates[@]}" = 1 ]
|
|
|
|
do
|
|
|
|
|
|
|
|
echo "Which Target Would You Like to Build?";
|
|
|
|
|
|
|
|
for j in $(seq 1 "${#targetCandidates[@]}")
|
|
|
|
do
|
|
|
|
index="${targetCandidates["$(expr $j - 1)"]}";
|
|
|
|
targetName="$(xmlstarlet select --template --match "$(getTargetXPath "$index")/TargetName" --value-of . "$projectFile")";
|
|
|
|
echo "$(printf "%${#targetCount}s" "$index"): \"$targetName\"";
|
|
|
|
done;
|
|
|
|
read -p "Enter your choice: " choice;
|
|
|
|
|
|
|
|
if [ $choice -gt 0 ] && [ $choice -le "${#targetCandidates[@]}" ]
|
|
|
|
then
|
|
|
|
targetCandidates=("${targetCandidates[$(expr $choice - 1)]}");
|
|
|
|
fi;
|
|
|
|
done;
|
|
|
|
|
|
|
|
return "${targetCandidates[0]}";
|
|
|
|
else
|
|
|
|
handle_status 1 "The current project '$projectFile' doesn't contain any targets!";
|
|
|
|
fi;
|
|
|
|
}
|
|
|
|
|
|
|
|
fileName="$(realpath "$1")";
|
2023-03-23 14:32:44 +00:00
|
|
|
test -f "$fileName";
|
|
|
|
handle_status "$?" "The specified file \"$1\" does not exist!";
|
2023-03-23 12:11:30 +00:00
|
|
|
|
|
|
|
if [[ "$fileName" =~ \.uvprojx$ ]]
|
|
|
|
then
|
|
|
|
projectFile="$fileName";
|
|
|
|
else
|
|
|
|
projectFile="$(find_project "$fileName")";
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ ! -z "$projectFile" ];
|
|
|
|
then
|
|
|
|
projectRoot="$(dirname "$projectFile")";
|
|
|
|
cd "$projectRoot";
|
|
|
|
tempFile="$(mktemp)";
|
|
|
|
cp -f "$projectFile" "$tempFile";
|
|
|
|
|
|
|
|
chooseTarget "$projectFile" "$fileName";
|
|
|
|
targetIndex="$?";
|
|
|
|
|
|
|
|
targetPath="$(getTargetXPath "$targetIndex")";
|
|
|
|
optionPath="$(getOptionPath "$targetIndex")";
|
|
|
|
|
|
|
|
fileCount="$(xmlstarlet select --template --copy-of "count($(getFileXPath))" "$projectFile")";
|
|
|
|
targetName="$(xmlstarlet select --template --match "$targetPath/TargetName" --value-of . "$projectFile")";
|
|
|
|
buildPath="$(xmlstarlet select --template --match "$optionPath/OutputDirectory" --value-of . "$projectFile")";
|
|
|
|
outputName="$(xmlstarlet select --template --match "$optionPath/OutputName" --value-of . "$projectFile")";
|
|
|
|
buildPath="$(normalize_path "$buildPath")";
|
|
|
|
outputName="$(normalize_path "$outputName")";
|
|
|
|
|
|
|
|
echo "Building Target \"$targetName\"";
|
|
|
|
echo "";
|
|
|
|
|
|
|
|
for i in $(seq 1 $fileCount)
|
|
|
|
do
|
|
|
|
xpath="($(getFileXPath))[$i]"
|
|
|
|
currentFileName="$(xmlstarlet select --template --match "$xpath" --value-of . "$projectFile")";
|
|
|
|
currentFileName="$(normalize_path "$currentFileName")";
|
|
|
|
xmlstarlet edit --inplace --update "$xpath" --value "$currentFileName" "$projectFile";
|
|
|
|
done;
|
|
|
|
|
|
|
|
logFile="$(mktemp)";
|
|
|
|
|
2023-04-01 13:02:51 +00:00
|
|
|
if is_truthy "${NATIVE_WINDOWS}"
|
|
|
|
then
|
|
|
|
PROJECT_FILE="$projectFile" LOG_FILE="$logFile" WSLENV="PROJECT_FILE/p:LOG_FILE/p" cmd.exe /c "C:\Keil_v5\UV4\UV4.exe" -j0 -b "%PROJECT_FILE%" -t "$targetName" -l "%LOG_FILE%";
|
|
|
|
else
|
|
|
|
WINEDEBUG=-all,fixme+event xvfb-run bash -c "dwm & wine \"C:\Keil_v5\UV4\UV4.exe\" -j0 -b \"$projectFile\" -t \"$targetName\" -l \"$logFile\"";
|
|
|
|
fi;
|
|
|
|
|
2023-03-23 12:11:30 +00:00
|
|
|
mv -f "$tempFile" "$projectFile";
|
|
|
|
|
2023-03-24 00:03:38 +00:00
|
|
|
errorPatterns=()
|
|
|
|
errorPatterns+=("\(\)\(.*\)\(([[:digit:]]\+): \(warning\|note\|error\): \([A-Z0-9]\+: \)\?.*\)$")
|
|
|
|
errorPatterns+=("\(\"\)\(.*\)\(\", line [[:digit:]]\+\( (column [[:digit:]]\+)\)\?: \(Warning\|Error\): [A-Z0-9]\+: .*\)$");
|
|
|
|
|
2023-04-01 13:02:32 +00:00
|
|
|
if is_truthy "${USE_WINDOWS_PATHS}"
|
2023-03-29 23:48:11 +00:00
|
|
|
then
|
|
|
|
fixCommand="wslpath -m";
|
|
|
|
else
|
|
|
|
fixCommand="realpath";
|
|
|
|
fi;
|
|
|
|
|
2023-03-24 00:03:38 +00:00
|
|
|
for errorPattern in "${errorPatterns[@]}"
|
|
|
|
do
|
|
|
|
sed -i \
|
|
|
|
-e "/$errorPattern/{" \
|
|
|
|
-e "h;" \
|
|
|
|
-e "s/$errorPattern/\1\n\3/" \
|
2023-03-29 23:48:11 +00:00
|
|
|
-e "x; s/$errorPattern/$fixCommand \"\2\"/" \
|
2023-03-24 00:03:38 +00:00
|
|
|
-e "e" \
|
|
|
|
-e "x; G; h;" \
|
|
|
|
-e "s/\([^\n]*\)\n//" \
|
|
|
|
-e "s/\([^\n]*\)\n\(.*\)/\2\1/" \
|
|
|
|
-e "x; s/\([^\n]*\)\n\(.*\)$/\1/" \
|
|
|
|
-e "G; s/\n//" \
|
|
|
|
-e "}" "$logFile";
|
|
|
|
done;
|
2023-03-23 12:11:30 +00:00
|
|
|
|
|
|
|
cat "$logFile";
|
|
|
|
|
|
|
|
if grep -q " 0 Error(s)" "$logFile";
|
|
|
|
then
|
|
|
|
outputName="$(realpath "$projectRoot/$buildPath/$outputName")";
|
|
|
|
outputFile="$outputName.axf";
|
2023-04-12 07:16:16 +00:00
|
|
|
echo "Target Built: \"$outputFile\".";
|
2023-03-23 12:11:30 +00:00
|
|
|
pyocd list | {
|
|
|
|
grep '^No available' &&
|
|
|
|
{
|
2023-04-12 07:16:16 +00:00
|
|
|
echo "Skpping Flash."
|
2023-03-23 12:11:30 +00:00
|
|
|
} ||
|
|
|
|
{
|
|
|
|
pyocd flash --target stm32f439xi "$outputFile";
|
2023-04-12 07:16:16 +00:00
|
|
|
handle_status $? "Flashing Failed";
|
2023-03-23 12:11:30 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
else
|
|
|
|
handle_status 1 "The project could not be built!";
|
|
|
|
fi;
|
|
|
|
else
|
2023-03-23 14:32:44 +00:00
|
|
|
handle_status 1 "No project file for \"${fileName}\" could be found."
|
2023-03-23 12:11:30 +00:00
|
|
|
fi;
|