xamarin-macios/tools/common/create-makefile-fragment.sh

125 строки
4.0 KiB
Bash
Executable File

#!/bin/bash -e
# This script takes a csproj as input and creates a file with a make variable
# that lists the input files for that csproj.
#
# The idea is to use this make variable as a dependency to a make rule that
# builds the csproj.
#
# The advantage of using make to determine if a csproj needs to be rebuilt is
# that it's much faster when nothing needs to be done: make takes ~0.015s to
# figure this out, msbuild takes ~1.5s. Multiply by the number of csprojs
# (currently 3: mtouch, mmp, generator) by the number of times built every day
# (dozens), and seconds adds up as years pass.
#
cd "$(dirname "$0")"
if test -z "$1"; then
echo "Must specify the project file to process."
exit 1
fi
# Input: the csproj file to process.
# Output: /path/to/proj.csproj.inc
PROJECT_FILE="$1"
PROJECT=$(basename -s .csproj "$PROJECT_FILE")
PROJECT_DIR=$(dirname "$PROJECT_FILE")
FRAGMENT_PATH="$2"
REFERENCES_PATH=$(pwd)/$PROJECT-references.txt
if test -z "$FRAGMENT_PATH"; then
FRAGMENT_PATH=$PROJECT_FILE.inc
fi
if test -z "$BUILD_EXECUTABLE"; then
BUILD_EXECUTABLE=msbuild
fi
# ProjectInspector.csproj is an MSBuild file with a target
# (WriteProjectReferences) that takes another project file as input (the
# ProjectFile variable) and writes all the project references (recursively) to
# a file (the ReferenceListPath variable).
(
cp ProjectInspector.csproj "$PROJECT_DIR"
cd "$PROJECT_DIR"
$BUILD_EXECUTABLE ProjectInspector.csproj "/t:WriteProjectReferences" "/p:ProjectFile=$PROJECT_FILE" "/p:ReferenceListPath=$REFERENCES_PATH" /verbosity:quiet /nologo
rm -f ProjectInspector.csproj
)
# Now we have a list of all the project referenced by the input project. The
# ProjectInspector.csproj also has a target (WriteInputs) that can list all
# the inputs for a project.
#
# The caveat here is that ProjectInspector.csproj must be in the same
# directory as the inspected project, because relative paths in the inspected
# project are evaluated according to the location of the main project file
# (our ProjectInspector.csproj). Relative paths can't be fixed manually
# afterwards, because relative paths with patterns (where MSBuild evaluates
# the patterns) won't come out right.
#
# So we copy ProjectInspector.csproj to the inspected project's directory and
# execute it from there.
TMPPROJ=
# Make sure we don't leave temporary files around
function delete_tmpproj
{
rm -f "$REFERENCES_PATH"
if test -n "$TMPPROJ"; then
rm -f "$TMPPROJ"
fi
}
trap delete_tmpproj EXIT
trap delete_tmpproj ERR
echo "$PROJECT_FILE" >> "$REFERENCES_PATH"
INPUT_PATHS=()
for proj in $(sort "$REFERENCES_PATH" | uniq); do
TMPPROJ=$PROJECT_DIR/ProjectInspector.csproj
# Copy ProjectInspector.csproj to target directory.
cp ProjectInspector.csproj "$TMPPROJ"
# Execute the WriteInputs target
proj_name=$(basename "$proj")
proj_dir=$(dirname "$proj")
inputs_path=$PWD/$proj_name.inputs
INPUT_PATHS+=("$inputs_path")
(
cd "$(dirname "$proj")"
$BUILD_EXECUTABLE "$TMPPROJ" "/t:WriteInputs" "/p:ProjectFile=$proj" "/p:InputsPath=$inputs_path" /verbosity:quiet /nologo
)
# The output contains relative paths, relative to the csproj directory
# Change those to full paths by prepending the csproj directory.
sed -i '' "s@^@$proj_dir/@" "$inputs_path"
# Change to Make syntax. This is horrifically difficult in MSBuild,
# because MSBuild blindly replaces backslashes with forward slashes (i.e.
# windows paths to unix paths...)
sed -i '' "s_^\\(.*\\)\$_ \\1 \\\\_" "$inputs_path"
# Clean up
rm -f "$TMPPROJ"
done
# Create the csproj.inc with the Makefile variable
# First add a dependency for the csproj.inc so that it's rebuilt if the project itself changes.
echo "${PROJECT}.csproj.inc: ${PROJECT_FILE} $PWD/ProjectInspector.csproj" > "$FRAGMENT_PATH"
# Now create the variable with all the input files.
echo "${PROJECT//-/_}_dependencies = \\" >> "$FRAGMENT_PATH"
sort "${INPUT_PATHS[@]}" | uniq >> "$FRAGMENT_PATH"
# Simplify paths somewhat by removing the current directory
if test -z "$ABSOLUTE_PATHS"; then
sed -i '' "s@$PROJECT_DIR/@@" "$FRAGMENT_PATH"
fi
# Cleanup
rm -f "${INPUT_PATHS[@]}"