From f48ba4530f3b1d23ac234c43a36e51eefd2c1bbc Mon Sep 17 00:00:00 2001 From: "Yifeng \"Evan\" Wang" <7312949+doodlewind@users.noreply.github.com> Date: Fri, 19 Jun 2026 15:30:00 +0800 Subject: [PATCH 1/6] Normalize PSP archive metadata --- scripts/006-normalize-llvm-psp-archives.sh | 164 +++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100755 scripts/006-normalize-llvm-psp-archives.sh diff --git a/scripts/006-normalize-llvm-psp-archives.sh b/scripts/006-normalize-llvm-psp-archives.sh new file mode 100755 index 0000000..4175a6b --- /dev/null +++ b/scripts/006-normalize-llvm-psp-archives.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [[ -z "${PSPDEV:-}" ]]; then + echo "ERROR: PSPDEV must be set before normalizing PSP archives." + exit 1 +fi + +LIB_DIR="${PSPDEV}/psp/lib" +if [[ ! -d "${LIB_DIR}" ]]; then + echo "No PSP library directory found at ${LIB_DIR}; skipping archive normalization." + exit 0 +fi + +find_tool() { + local tool="$1" + if command -v "${tool}" >/dev/null 2>&1; then + command -v "${tool}" + return 0 + fi + + if command -v brew >/dev/null 2>&1; then + local brew_llvm + brew_llvm="$(brew --prefix llvm 2>/dev/null || true)" + if [[ -n "${brew_llvm}" && -x "${brew_llvm}/bin/${tool}" ]]; then + echo "${brew_llvm}/bin/${tool}" + return 0 + fi + fi + + for prefix in /opt/homebrew/opt/llvm /usr/local/opt/llvm; do + if [[ -x "${prefix}/bin/${tool}" ]]; then + echo "${prefix}/bin/${tool}" + return 0 + fi + done + + echo "ERROR: ${tool} not found. Install LLVM before running this step." >&2 + return 1 +} + +LLVM_AR="$(find_tool llvm-ar)" +LLVM_RANLIB="$(find_tool llvm-ranlib)" +LLVM_READELF="$(find_tool llvm-readelf)" +LLVM_OBJCOPY="$(find_tool llvm-objcopy)" + +if ! command -v perl >/dev/null 2>&1; then + echo "ERROR: perl not found. A system Perl is required for ELF metadata normalization." + exit 1 +fi + +WORK_DIR="$(mktemp -d "${TMPDIR:-/tmp}/pspdev-normalize-archives.XXXXXX")" +trap 'rm -rf "${WORK_DIR}"' EXIT + +PATCH_ELF="${WORK_DIR}/patch-mips-psp-elf.pl" +cat > "${PATCH_ELF}" <<'PERL' +use strict; +use warnings; + +for my $path (@ARGV) { + open(my $fh, "+<:raw", $path) or die "open $path: $!"; + local $/; + my $data = <$fh>; + next unless length($data) >= 52; + next unless substr($data, 0, 4) eq "\x7fELF"; + next unless unpack("C", substr($data, 4, 1)) == 1; # ELFCLASS32 + next unless unpack("C", substr($data, 5, 1)) == 1; # ELFDATA2LSB + next unless unpack("v", substr($data, 18, 2)) == 8; # EM_MIPS + + # Clang's MIPS objects can carry machine-extension and single-float metadata + # that rust-lld rejects when linked with rustc's current mipsel-sony-psp + # objects. Match the metadata shape emitted by rustc and the legacy PSP SDK: + # MIPS2 O32, no machine extension, hard-float double ABI. + my $flags = unpack("V", substr($data, 36, 4)); + substr($data, 36, 4) = pack("V", $flags & 0xf000ffff); + + my $shoff = unpack("V", substr($data, 32, 4)); + my $shentsize = unpack("v", substr($data, 46, 2)); + my $shnum = unpack("v", substr($data, 48, 2)); + my $shstrndx = unpack("v", substr($data, 50, 2)); + if ($shoff && $shentsize && $shstrndx < $shnum) { + my $shstr = $shoff + $shstrndx * $shentsize; + if ($shstr + 24 <= length($data)) { + my $shstr_off = unpack("V", substr($data, $shstr + 16, 4)); + my $shstr_size = unpack("V", substr($data, $shstr + 20, 4)); + my $shstr_end = $shstr_off + $shstr_size; + if ($shstr_end <= length($data)) { + for (my $i = 0; $i < $shnum; $i++) { + my $sh = $shoff + $i * $shentsize; + next if $sh + 24 > length($data); + my $name_off = unpack("V", substr($data, $sh, 4)); + my $name_start = $shstr_off + $name_off; + next if $name_start >= $shstr_end; + my $name_end = index($data, "\0", $name_start); + next if $name_end < 0 || $name_end > $shstr_end; + my $name = substr($data, $name_start, $name_end - $name_start); + next unless $name eq ".MIPS.abiflags"; + + my $off = unpack("V", substr($data, $sh + 16, 4)); + my $size = unpack("V", substr($data, $sh + 20, 4)); + next if $size < 24 || $off + $size > length($data); + substr($data, $off + 7, 1) = "\x01"; # Val_GNU_MIPS_ABI_FP_DOUBLE + substr($data, $off + 8, 4) = pack("V", 0); # ISA extension: none + substr($data, $off + 12, 4) = pack("V", 0); # ASEs: none + substr($data, $off + 16, 4) = pack("V", 1); # FLAGS1: odd single-precision regs + } + } + } + } + + seek($fh, 0, 0) or die "seek $path: $!"; + print {$fh} $data or die "write $path: $!"; + truncate($fh, length($data)) or die "truncate $path: $!"; + close($fh) or die "close $path: $!"; +} +PERL + +normalize_archive() { + local archive="$1" + local name + name="$(basename "${archive}")" + local archive_dir="${WORK_DIR}/${name%.a}" + mkdir -p "${archive_dir}" + + ( + cd "${archive_dir}" + "${LLVM_AR}" x "${archive}" + ) + + local changed=0 + while IFS= read -r obj; do + local file_symbols + file_symbols="$("${LLVM_READELF}" -s "${obj}" | awk '$4 == "FILE" && $5 == "LOCAL" && $8 != "" { print $8 }' | sort -u)" + if [[ -n "${file_symbols}" ]]; then + changed=1 + local strip_args=() + while IFS= read -r sym; do + strip_args+=("--strip-symbol=${sym}") + done <<< "${file_symbols}" + "${LLVM_OBJCOPY}" "${strip_args[@]}" "${obj}" + fi + done < <(find "${archive_dir}" -type f -name "*.o" | sort) + + perl "${PATCH_ELF}" "${archive_dir}"/*.o + + rm -f "${archive}" + ( + cd "${archive_dir}" + "${LLVM_AR}" rc "${archive}" ./*.o + ) + "${LLVM_RANLIB}" "${archive}" + + if [[ "${changed}" -eq 1 ]]; then + echo "Normalized PSP archive symbols and metadata: ${name}" + else + echo "Normalized PSP archive metadata: ${name}" + fi +} + +for archive in "${LIB_DIR}"/*.a; do + [[ -e "${archive}" ]] || continue + normalize_archive "${archive}" +done From 0db3b61a10a250af3525c9f171cde75fa5ef9f98 Mon Sep 17 00:00:00 2001 From: "Yifeng \"Evan\" Wang" <7312949+doodlewind@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:10:26 +0800 Subject: [PATCH 2/6] Normalize PSP archives before package builds --- scripts/003-normalize-llvm-psp-archives.sh | 9 +++++++++ scripts/006-normalize-llvm-psp-archives.sh | 21 +++++++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100755 scripts/003-normalize-llvm-psp-archives.sh diff --git a/scripts/003-normalize-llvm-psp-archives.sh b/scripts/003-normalize-llvm-psp-archives.sh new file mode 100755 index 0000000..96013b8 --- /dev/null +++ b/scripts/003-normalize-llvm-psp-archives.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Normalize the core PSPSDK archives before psp-packages and psplink build +# against them. The final normalization step runs again after packages install +# their own archives. +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +"${SCRIPT_DIR}/006-normalize-llvm-psp-archives.sh" diff --git a/scripts/006-normalize-llvm-psp-archives.sh b/scripts/006-normalize-llvm-psp-archives.sh index 4175a6b..2097e68 100755 --- a/scripts/006-normalize-llvm-psp-archives.sh +++ b/scripts/006-normalize-llvm-psp-archives.sh @@ -128,10 +128,17 @@ normalize_archive() { "${LLVM_AR}" x "${archive}" ) + local member_list="${WORK_DIR}/${name%.a}.members" + find "${archive_dir}" -type f | sort > "${member_list}" + if [[ ! -s "${member_list}" ]]; then + echo "Skipping empty PSP archive: ${name}" + return + fi + local changed=0 while IFS= read -r obj; do local file_symbols - file_symbols="$("${LLVM_READELF}" -s "${obj}" | awk '$4 == "FILE" && $5 == "LOCAL" && $8 != "" { print $8 }' | sort -u)" + file_symbols="$("${LLVM_READELF}" -s "${obj}" 2>/dev/null | awk '$4 == "FILE" && $5 == "LOCAL" && $8 != "" { print $8 }' | sort -u || true)" if [[ -n "${file_symbols}" ]]; then changed=1 local strip_args=() @@ -140,14 +147,20 @@ normalize_archive() { done <<< "${file_symbols}" "${LLVM_OBJCOPY}" "${strip_args[@]}" "${obj}" fi - done < <(find "${archive_dir}" -type f -name "*.o" | sort) + done < "${member_list}" - perl "${PATCH_ELF}" "${archive_dir}"/*.o + while IFS= read -r obj; do + perl "${PATCH_ELF}" "${obj}" + done < "${member_list}" rm -f "${archive}" + local members=() + while IFS= read -r obj; do + members+=("${obj#${archive_dir}/}") + done < "${member_list}" ( cd "${archive_dir}" - "${LLVM_AR}" rc "${archive}" ./*.o + "${LLVM_AR}" rc "${archive}" "${members[@]}" ) "${LLVM_RANLIB}" "${archive}" From 3d05680d976d8df8122424f9019befe12dad3b63 Mon Sep 17 00:00:00 2001 From: "Yifeng \"Evan\" Wang" <7312949+doodlewind@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:45:24 +0800 Subject: [PATCH 3/6] Keep GNU MIPS FP metadata consistent --- scripts/006-normalize-llvm-psp-archives.sh | 33 ++++++++++++++++------ 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/scripts/006-normalize-llvm-psp-archives.sh b/scripts/006-normalize-llvm-psp-archives.sh index 2097e68..3be7747 100755 --- a/scripts/006-normalize-llvm-psp-archives.sh +++ b/scripts/006-normalize-llvm-psp-archives.sh @@ -95,15 +95,30 @@ for my $path (@ARGV) { my $name_end = index($data, "\0", $name_start); next if $name_end < 0 || $name_end > $shstr_end; my $name = substr($data, $name_start, $name_end - $name_start); - next unless $name eq ".MIPS.abiflags"; - - my $off = unpack("V", substr($data, $sh + 16, 4)); - my $size = unpack("V", substr($data, $sh + 20, 4)); - next if $size < 24 || $off + $size > length($data); - substr($data, $off + 7, 1) = "\x01"; # Val_GNU_MIPS_ABI_FP_DOUBLE - substr($data, $off + 8, 4) = pack("V", 0); # ISA extension: none - substr($data, $off + 12, 4) = pack("V", 0); # ASEs: none - substr($data, $off + 16, 4) = pack("V", 1); # FLAGS1: odd single-precision regs + + if ($name eq ".MIPS.abiflags") { + my $off = unpack("V", substr($data, $sh + 16, 4)); + my $size = unpack("V", substr($data, $sh + 20, 4)); + next if $size < 24 || $off + $size > length($data); + substr($data, $off + 7, 1) = "\x01"; # Val_GNU_MIPS_ABI_FP_DOUBLE + substr($data, $off + 8, 4) = pack("V", 0); # ISA extension: none + substr($data, $off + 12, 4) = pack("V", 0); # ASEs: none + substr($data, $off + 16, 4) = pack("V", 1); # FLAGS1: odd single-precision regs + } + + if ($name eq ".gnu.attributes") { + my $off = unpack("V", substr($data, $sh + 16, 4)); + my $size = unpack("V", substr($data, $sh + 20, 4)); + next if $off + $size > length($data); + + my $attrs = substr($data, $off, $size); + # GNU MIPS Tag_GNU_MIPS_ABI_FP is encoded as tag 4 followed + # by a small uleb128 value. Clang emits value 2 here while + # the SDK/rustc-compatible .MIPS.abiflags metadata says + # double-float. Keep both metadata sources in sync. + $attrs =~ s/\x04\x02/\x04\x01/g; + substr($data, $off, $size) = $attrs; + } } } } From 96b07a7bb3a629afe205061ec0d6ffe7def2ae25 Mon Sep 17 00:00:00 2001 From: "Yifeng \"Evan\" Wang" <7312949+doodlewind@users.noreply.github.com> Date: Fri, 19 Jun 2026 17:27:32 +0800 Subject: [PATCH 4/6] Align psplinkusb FP metadata with SDK archives --- scripts/004-psplinkusb-extra.sh | 91 +++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/scripts/004-psplinkusb-extra.sh b/scripts/004-psplinkusb-extra.sh index a261aff..4ec664c 100755 --- a/scripts/004-psplinkusb-extra.sh +++ b/scripts/004-psplinkusb-extra.sh @@ -11,6 +11,97 @@ else cd $REPO_FOLDER && git fetch origin && git reset --hard origin/${BRANCH_NAME} || { exit 1; } fi +## The clang-built SDK archives are normalized to rustc-compatible double-float +## metadata. Keep psplinkusb's PSP-side object metadata consistent with those +## archives so BFD ld does not warn while linking these helper PRX/ELF files. +## Do this after compilation instead of changing CFLAGS, because psplinkusb +## contains real float/double code and should keep its original codegen. +NORMALIZE_OBJECTS="$PWD/normalize-psp-object-metadata.sh" +cat > "$NORMALIZE_OBJECTS" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail + +[[ "$#" -eq 0 ]] && exit 0 + +perl - "$@" <<'PERL' +use strict; +use warnings; + +for my $path (@ARGV) { + open(my $fh, "+<:raw", $path) or die "open $path: $!"; + local $/; + my $data = <$fh>; + next unless length($data) >= 52; + next unless substr($data, 0, 4) eq "\x7fELF"; + next unless unpack("C", substr($data, 4, 1)) == 1; # ELFCLASS32 + next unless unpack("C", substr($data, 5, 1)) == 1; # ELFDATA2LSB + next unless unpack("v", substr($data, 18, 2)) == 8; # EM_MIPS + + my $flags = unpack("V", substr($data, 36, 4)); + substr($data, 36, 4) = pack("V", $flags & 0xf000ffff); + + my $shoff = unpack("V", substr($data, 32, 4)); + my $shentsize = unpack("v", substr($data, 46, 2)); + my $shnum = unpack("v", substr($data, 48, 2)); + my $shstrndx = unpack("v", substr($data, 50, 2)); + if ($shoff && $shentsize && $shstrndx < $shnum) { + my $shstr = $shoff + $shstrndx * $shentsize; + if ($shstr + 24 <= length($data)) { + my $shstr_off = unpack("V", substr($data, $shstr + 16, 4)); + my $shstr_size = unpack("V", substr($data, $shstr + 20, 4)); + my $shstr_end = $shstr_off + $shstr_size; + if ($shstr_end <= length($data)) { + for (my $i = 0; $i < $shnum; $i++) { + my $sh = $shoff + $i * $shentsize; + next if $sh + 24 > length($data); + my $name_off = unpack("V", substr($data, $sh, 4)); + my $name_start = $shstr_off + $name_off; + next if $name_start >= $shstr_end; + my $name_end = index($data, "\0", $name_start); + next if $name_end < 0 || $name_end > $shstr_end; + my $name = substr($data, $name_start, $name_end - $name_start); + + if ($name eq ".MIPS.abiflags") { + my $off = unpack("V", substr($data, $sh + 16, 4)); + my $size = unpack("V", substr($data, $sh + 20, 4)); + next if $size < 24 || $off + $size > length($data); + substr($data, $off + 7, 1) = "\x01"; + substr($data, $off + 8, 4) = pack("V", 0); + substr($data, $off + 12, 4) = pack("V", 0); + substr($data, $off + 16, 4) = pack("V", 1); + } + + if ($name eq ".gnu.attributes") { + my $off = unpack("V", substr($data, $sh + 16, 4)); + my $size = unpack("V", substr($data, $sh + 20, 4)); + next if $off + $size > length($data); + my $attrs = substr($data, $off, $size); + $attrs =~ s/\x04\x02/\x04\x01/g; + substr($data, $off, $size) = $attrs; + } + } + } + } + } + + seek($fh, 0, 0) or die "seek $path: $!"; + print {$fh} $data or die "write $path: $!"; + truncate($fh, length($data)) or die "truncate $path: $!"; + close($fh) or die "close $path: $!"; +} +PERL +EOF +chmod +x "$NORMALIZE_OBJECTS" +export PSPLINKUSB_NORMALIZE_OBJECTS="$NORMALIZE_OBJECTS" + +while IFS= read -r MAKEFILE; do + perl -0pi -e 's/(\nPSPSDK=\$\(shell psp-config --pspsdk-path\)\ninclude \$\(PSPSDK\)\/lib\/build[^ \n]*\.mak\n)/\n.PHONY: normalize-psp-objects\n\$(TARGET).elf: | normalize-psp-objects\nnormalize-psp-objects: \$(OBJS)\n\t\$(PSPLINKUSB_NORMALIZE_OBJECTS) \$(OBJS)\n$1/s' "$MAKEFILE" +done < <(find . -name Makefile -type f -exec grep -l '\$(PSPSDK)/lib/build' {} +) + +for MAKEFILE in libpsplink/Makefile libpsplink_driver/Makefile libusbhostfs/Makefile libusbhostfs_driver/Makefile; do + perl -0pi -e 's/\n\$\((TARGET)\): \$\((OBJS)\)/\n.PHONY: normalize-psp-objects\nnormalize-psp-objects: \$(OBJS)\n\t\$(PSPLINKUSB_NORMALIZE_OBJECTS) \$(OBJS)\n\n\$(TARGET): \$(OBJS) | normalize-psp-objects/' "$MAKEFILE" +done + ## Determine the maximum number of processes that Make can work with. PROC_NR=$(getconf _NPROCESSORS_ONLN) OSVER=$(uname) From 806b563b3a6749e9ef54638acbf8aef4aee36e4a Mon Sep 17 00:00:00 2001 From: "Yifeng \"Evan\" Wang" <7312949+doodlewind@users.noreply.github.com> Date: Fri, 19 Jun 2026 18:13:51 +0800 Subject: [PATCH 5/6] Normalize PSP import and GCC runtime archives --- scripts/006-normalize-llvm-psp-archives.sh | 39 ++++++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/scripts/006-normalize-llvm-psp-archives.sh b/scripts/006-normalize-llvm-psp-archives.sh index 3be7747..f417dc5 100755 --- a/scripts/006-normalize-llvm-psp-archives.sh +++ b/scripts/006-normalize-llvm-psp-archives.sh @@ -7,9 +7,24 @@ if [[ -z "${PSPDEV:-}" ]]; then exit 1 fi -LIB_DIR="${PSPDEV}/psp/lib" -if [[ ! -d "${LIB_DIR}" ]]; then - echo "No PSP library directory found at ${LIB_DIR}; skipping archive normalization." +ARCHIVE_DIRS=() +add_archive_dir() { + local dir="$1" + if [[ -d "${dir}" ]]; then + ARCHIVE_DIRS+=("${dir}") + fi +} + +add_archive_dir "${PSPDEV}/psp/lib" +add_archive_dir "${PSPDEV}/psp/sdk/lib" +if [[ -d "${PSPDEV}/lib/gcc/psp" ]]; then + while IFS= read -r dir; do + add_archive_dir "${dir}" + done < <(find "${PSPDEV}/lib/gcc/psp" -mindepth 1 -maxdepth 1 -type d | sort) +fi + +if [[ "${#ARCHIVE_DIRS[@]}" -eq 0 ]]; then + echo "No PSP archive directories found under ${PSPDEV}; skipping archive normalization." exit 0 fi @@ -135,8 +150,8 @@ normalize_archive() { local archive="$1" local name name="$(basename "${archive}")" - local archive_dir="${WORK_DIR}/${name%.a}" - mkdir -p "${archive_dir}" + local archive_dir + archive_dir="$(mktemp -d "${WORK_DIR}/${name%.a}.XXXXXX")" ( cd "${archive_dir}" @@ -146,7 +161,7 @@ normalize_archive() { local member_list="${WORK_DIR}/${name%.a}.members" find "${archive_dir}" -type f | sort > "${member_list}" if [[ ! -s "${member_list}" ]]; then - echo "Skipping empty PSP archive: ${name}" + echo "Skipping empty PSP archive: ${archive#${PSPDEV}/}" return fi @@ -180,13 +195,15 @@ normalize_archive() { "${LLVM_RANLIB}" "${archive}" if [[ "${changed}" -eq 1 ]]; then - echo "Normalized PSP archive symbols and metadata: ${name}" + echo "Normalized PSP archive symbols and metadata: ${archive#${PSPDEV}/}" else - echo "Normalized PSP archive metadata: ${name}" + echo "Normalized PSP archive metadata: ${archive#${PSPDEV}/}" fi } -for archive in "${LIB_DIR}"/*.a; do - [[ -e "${archive}" ]] || continue - normalize_archive "${archive}" +for dir in "${ARCHIVE_DIRS[@]}"; do + for archive in "${dir}"/*.a; do + [[ -e "${archive}" ]] || continue + normalize_archive "${archive}" + done done From e9e6c2ea26a6965649337bbb3afd8c3228580235 Mon Sep 17 00:00:00 2001 From: "Yifeng \"Evan\" Wang" <7312949+doodlewind@users.noreply.github.com> Date: Fri, 19 Jun 2026 18:51:38 +0800 Subject: [PATCH 6/6] Normalize psplinkusb export objects before linking --- scripts/004-psplinkusb-extra.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/004-psplinkusb-extra.sh b/scripts/004-psplinkusb-extra.sh index 4ec664c..9ae1d94 100755 --- a/scripts/004-psplinkusb-extra.sh +++ b/scripts/004-psplinkusb-extra.sh @@ -95,7 +95,7 @@ chmod +x "$NORMALIZE_OBJECTS" export PSPLINKUSB_NORMALIZE_OBJECTS="$NORMALIZE_OBJECTS" while IFS= read -r MAKEFILE; do - perl -0pi -e 's/(\nPSPSDK=\$\(shell psp-config --pspsdk-path\)\ninclude \$\(PSPSDK\)\/lib\/build[^ \n]*\.mak\n)/\n.PHONY: normalize-psp-objects\n\$(TARGET).elf: | normalize-psp-objects\nnormalize-psp-objects: \$(OBJS)\n\t\$(PSPLINKUSB_NORMALIZE_OBJECTS) \$(OBJS)\n$1/s' "$MAKEFILE" + perl -0pi -e 's/(\nPSPSDK=\$\(shell psp-config --pspsdk-path\)\ninclude \$\(PSPSDK\)\/lib\/build[^ \n]*\.mak\n)/$1\n.PHONY: normalize-psp-objects\n\$(TARGET).elf: | normalize-psp-objects\nnormalize-psp-objects: \$(OBJS) \$(EXPORT_OBJ)\n\t\$(PSPLINKUSB_NORMALIZE_OBJECTS) \$(OBJS) \$(EXPORT_OBJ)\n/s' "$MAKEFILE" done < <(find . -name Makefile -type f -exec grep -l '\$(PSPSDK)/lib/build' {} +) for MAKEFILE in libpsplink/Makefile libpsplink_driver/Makefile libusbhostfs/Makefile libusbhostfs_driver/Makefile; do