Reputation: 133159
Starting with Xcode 10, build script phases can use file lists (.xcfilelist
) for input and output instead of specifying input/output files directly. Those files seem to support comments (the WWDC sample showed command line comments on top), blank lines (also in the sample), and otherwise expect one file path per line. If these file contain build settings (e.g. $(SRCROOT)
), these are expanded prior to calling the script, just like they would have been expanded if the file path was directly given as input/output file.
This sounds like a great feature but how would you use these file lists in your actual script?
When specifying the files directly, you had the shell variables SCRIPT_INPUT_FILE_COUNT
and SCRIPT_OUTPUT_FILE_COUNT
and then one variable for each input/output file, named SCRIPT_INPUT_FILE_#
and SCRIPT_OUTPUT_FILE_#
where #
used to be an up-counting number. Assuming that you have an equal number of input/output file, this script would print them all:
#!/bin/sh
: $((i=0))
while [ $i -lt "$SCRIPT_INPUT_FILE_COUNT" ]
do
eval fileIn="\$SCRIPT_INPUT_FILE_${i}"
eval fileOut="\$SCRIPT_OUTPUT_FILE_${i}"
echo "$fileIn --> $fileOut"
: $((i=i+1))
done
This is a clean POSIX compatible shell script, yes, you can make it even nicer when requiring bash
but the code above should work with every sh
compatible shell (which it also promisses when using #!/bin/sh
and not #!/bin/bash
).
But when using file lists, SCRIPT_INPUT_FILE_COUNT
is 0. Instead you get SCRIPT_INPUT_FILE_LIST_COUNT
and SCRIPT_OUTPUT_FILE_LIST_COUNT
, and the variables SCRIPT_INPUT_FILE_LIST_#
and SCRIPT_OUTPUT_FILE_LIST_#
, containing the paths to the pre-processed file lists, where all comments and blank lines have been stripped and all build settings have already been expanded.
Now, how would I go about using these file lists in my script? How would the tiny sample script above produce the same output using file lists in Xcode? I'm not really good at shell scripting and I'm looking for a clean solution that doesn't require any other script interpreter but sh
.
Upvotes: 8
Views: 5575
Reputation: 897
This will dynamically construct the SCRIPT_INPUT_FILE_LIST_0
, SCRIPT_INPUT_FILE_LIST_1
, etc. values and access them from the environment vars passed to the script by Xcode. Swap out the echo "${file_path}"
line if you want to do something other than printing each of the lines from the xcfilelist
(s).
#!/usr/bin/env bash
for index in $(seq $SCRIPT_INPUT_FILE_LIST_COUNT); do
# 1 => `SCRIPT_INPUT_FILE_LIST_0`
filelist=SCRIPT_INPUT_FILE_LIST_$((index-1))
# `SCRIPT_INPUT_FILE_LIST_0` => value in $SCRIPT_INPUT_FILE_LIST_0
filelist_path=${!filelist}
while read -r file_path; do
echo "${file_path}"
done <$filelist_path
done
Upvotes: 3
Reputation: 8963
I'm not aware of a way to get access to the file list itself inside the shellscript. However, the idea of a file list is you ideally have one for however many files there are. So, I usually hardcode it to the same value I gave xcode. It's a bit duplicated, but not a whole lot:
set -e
while read file; do
EXPANDED=`eval echo "$file"`
echo "do something with $EXPANDED"
done <"${SRCROOT}/path/to/files.xcfileslist"
As a side effect of this read
device we strip whitespace and do some other light processing. If you are particular about how you want this to happen, see this SO answer.
I believe most (all?) build settings are exported into the script as environment variables. So by evaluating them with eval
here we expand them.
Use of eval
opens up the possibility that a malicious file list can execute code. Then again it's probably located in the same place as the build script you're executing so I'm not sure it's a very practical problem. Other shells have more secure ways of going about this, but I'm not aware of any for vanilla sh
and default macOS.
Upvotes: 0