You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
6.5 KiB

#!/bin/sh
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This file is part of dobuild.
# Copyright (c) 2019 Contributors as noted in the AUTHORS file.
#
# SPDX-License-Identifier: MPL-2.0
set -e
# FIXME: don't depend on cmake internals
discover_cmake_includes() {
if [ $# -gt 0 ]; then
sed -n -e 's/.*_INCLUDE_DIRS:INTERNAL=\(.*\)$/\1/p' "$@";
fi
}
discover_system_includes() {
case "$BUILDSYSTEM" in
cmake-?*)
discover_cmake_includes "$@"
;;
*)
;;
esac
}
# FIXME: handle different compilers and language standards
discover_cc_includes() {
{
echo | "$CXX" -xc++ -E -Wp,-v - 2>&1
echo | "$CC" -xc -E -Wp,-v - 2>&1
} \
| sed -n -e 's/\s\+\(\/.*$\).*/\1/p'
}
discover_includes() {
{
discover_cc_includes;
discover_system_includes "$@"
} \
| sed 's/;/\n/g' | sed '/^$/d' | sort -u 2>/dev/null \
| while IFS= read -r file; do
if [ -e "$file" ]; then
canonicalize "$file"
fi
done
}
detect_toolchain() {
case "$BUILDSYSTEM" in
cmake-?*)
cmake -LA -N "$(dirname "$1")" > "$CACHED_VALUES_TMPFILE"
CXX="$(sed -n -e 's/CMAKE_CXX_COMPILER:FILEPATH=\(.*\)$/\1/p' -e 's/CMAKE_CXX_COMPILER:STRING=\(.*\)$/\1/p' "$CACHED_VALUES_TMPFILE")"
CC="$(sed -n -e 's/CMAKE_C_COMPILER:FILEPATH=\(.*\)$/\1/p' -e 's/CMAKE_C_COMPILER:STRING=\(.*\)$/\1/p' "$CACHED_VALUES_TMPFILE")"
;;
*)
;;
esac
}
parse_make_targets() {
parse_make_targets.sh -C "$WORKINGDIR"
}
parse_ninja_targets() {
"$NINJA" -C "$WORKINGDIR" -t targets all | sed -n -e 's/\([^:]*\):.*/\1/p' | sort 2>/dev/null
}
discover_targets() {
case "$BUILDSYSTEM" in
cmake-make|make)
parse_make_targets
;;
cmake-ninja|ninja)
parse_ninja_targets
;;
*)
;;
esac
}
prefix_dir() {
while IFS= read -r dir; do
printf '%s%s\n' "$1" "$dir"
done
}
sed_keyword() {
printf '%s\n' "$@" | sed -e 's/[]\/$*.^[]/\\&/g'
}
sed_replacement() {
printf '%s\n' "$@" | sed -e 's/[\/&]/\\&/g'
}
format_json() {
i=0
printf '[\n'
while IFS= read -r line; do
if [ "$i" -gt 0 ]; then
printf ',\n'
fi
printf '"%s"' "$line"
i="$((i+1))"
done
printf '\n]\n'
}
physical_pwd() {
pwd -P 2>/dev/null || pwd
}
try_canonicalize() {
readlink -f "$@" 2>/dev/null || realpath "$@"
}
canonicalize() {
if ! try_canonicalize "$1" 2>/dev/null; then
echo "$(cd "$(dirname "$1")" && physical_pwd)/$(basename "$1")"
fi
}
scriptdir() {
dirname "$(canonicalize "${BASH_SOURCE:-$1}")"
}
cleanup() {
EXITCODE="${EXITCODE:-$?}"
rm -f "$INCLUDE_DIRS_TMPFILE" "$CACHED_VALUES_TMPFILE"
return "$EXITCODE"
}
trap cleanup TERM INT EXIT
export LANG=C
export LC_ALL=C
DOBUILDDIR="${DOBUILDDIR:-"$(dirname "$(scriptdir "$0")")"}"
NINJA="${NINJA:-ninja}"
PATH="$DOBUILDDIR/bin:$PATH"
set -- "$@" --
CXX=
CC=
BUILDSYSTEM=
WORKINGDIR="$PWD"
PROJECTDIR=
INCLUDE_PREFIX="$WORKINGDIR"
COMPILE_COMMANDS_JSON_FILE=
while :; do
case $1 in
-C|--directory)
if [ "$2" != '--' ]; then
WORKINGDIR="$2"
shift
else
printf 'error: "%s" requires a non-empty option argument.\n' "$1" >&2
exit 3
fi
;;
--directory=)
printf 'error: "%s" requires a non-empty option argument.\n' "$1" >&2
exit 3
;;
--directory=?*)
WORKINGDIR="${1#*=}"
;;
--project-root)
if [ "$2" != '--' ]; then
PROJECTDIR="$2"
shift
else
PROJECTDIR=
fi
;;
--project-root=)
PROJECTDIR=
;;
--project-root=?*)
PROJECTDIR="${1#*=}"
;;
--build-system)
if [ "$2" != '--' ]; then
BUILDSYSTEM="$2"
shift
else
BUILDSYSTEM=
fi
;;
--build-system=)
BUILDSYSTEM=
;;
--build-system=?*)
BUILDSYSTEM="${1#*=}"
;;
-p|--include-prefix)
if [ "$2" != '--' ]; then
INCLUDE_PREFIX="$2"
shift
else
INCLUDE_PREFIX=
fi
;;
--include-prefix=)
INCLUDE_PREFIX=
;;
--include-prefix=?*)
INCLUDE_PREFIX="${1#*=}"
;;
compile_commands.json|?*/compile_commands.json)
COMPILE_COMMANDS_JSON_FILE="$1"
;;
--help)
{
printf 'Usage: %s [option...] [file...]\n' "$(basename "$0")"
printf 'Options:\n'
printf '\t-C|--directory\t\tWorking directory\n'
printf '\t--build-system\t\tBuildsystem kind e.g. cmake-make,cmake-ninja\n'
printf '\t--project-root\t\tProject root directory\n'
printf '\t-p|--include-prefix\tInclude prefix appended to all discovered include dirs\n'
printf 'Files:\n'
printf '\tBuildsystem specific configurations files e.g. CMakeCache.txt\n'
} >&2
exit 0
;;
--)
shift
break
;;
*)
set -- "$@" "$1"
;;
esac
shift
done
OUTDIR="$WORKINGDIR/DoBuildFiles"
mkdir -p "$OUTDIR"
INCLUDE_PREFIX_REPLACEMENT="%OUTDIR%/$INCLUDE_PREFIX"
CACHED_VALUES_TMPFILE="$(mktemp -p "$OUTDIR" cached_values_XXXXXXXXXX.txt)"
INCLUDE_DIRS_TMPFILE="$(mktemp -p "$OUTDIR" include_dirs_XXXXXXXXXX.txt)"
INCLUDE_DIRS_TMPL_FILE="$OUTDIR/include_dirs.json.template"
TARGETS_JSON_FILE="$OUTDIR/targets.json"
TARGETS_TXT_FILE="$OUTDIR/targets.txt"
COMPILE_COMMANDS_TMPL_FILE="$OUTDIR/compile_commands.json.template"
C_BUILTIN_FILE="$OUTDIR/builtins.h"
CXX_BUILTIN_FILE="$OUTDIR/builtins.hpp"
detect_toolchain "$@"
discover_targets "$@" | tee "$TARGETS_TXT_FILE" | format_json > "$TARGETS_JSON_FILE"
discover_includes "$@" | tee "$INCLUDE_DIRS_TMPFILE" | prefix_dir "$INCLUDE_PREFIX_REPLACEMENT" | format_json > "$INCLUDE_DIRS_TMPL_FILE"
# FIXME: handle different compilers and language standards
"$CC" -xc -dM -E - < /dev/null > "$C_BUILTIN_FILE"
"$CXX" -xc++ -dM -E - < /dev/null > "$CXX_BUILTIN_FILE"
if [ -n "$COMPILE_COMMANDS_JSON_FILE" ]; then
set --
while IFS= read -r line; do
set -- "$@" -e "s/$(sed_keyword "${line}")/$(sed_replacement "${INCLUDE_PREFIX_REPLACEMENT}${line}")/g"
done < "$INCLUDE_DIRS_TMPFILE"
set -- "$@" -e "s/$(sed_keyword "$WORKINGDIR")/$(sed_replacement "%OUTDIR%")/g"
if [ -n "$PROJECTDIR" ]; then
set -- "$@" -e "s/$(sed_keyword "$PROJECTDIR")/$(sed_replacement "%PROJECTDIR%")/g"
fi
set -- "$@" "$COMPILE_COMMANDS_JSON_FILE"
sed "$@" > "$COMPILE_COMMANDS_TMPL_FILE"
fi
set --
if [ -n "$INCLUDE_PREFIX" ]; then
while IFS= read -r file; do
set -- "$@" "$file"
done < "$INCLUDE_DIRS_TMPFILE"
fi
cleanup
exec tar cf - -C / "$@"