summaryrefslogtreecommitdiffstats
path: root/make/xcodemake
blob: dfa03643e85b6e3e26b08f61130602ff2df427d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#!/usr/bin/env bash
#

set -e

## This script is initiated by either xcodebuild or Xcode.app.
##
## We must guarantee no jobserver is passed through since file-descriptors are
## clobbered by Xcode. If this is not done then make allows unlimited jobs.
##
MAKEFLAGS=
MFLAGS=

## validate environment
case "$EXTERNAL_DRIVER" in
bootstrap) ;; ## bootstrapping from terminal
terminal)  ;; ## building from terminal
xcode)     ;; ## building from Xcode.app
*)
    echo "ERROR: unexpected value for EXTERNAL_DRIVER: $EXTERNAL_DRIVER"
    exit 1
    ;;
esac

## validate environment
for name in EXTERNAL_BUILD EXTERNAL_JOBS EXTERNAL_SRC; do
    eval v="\$$name"
    if [ -z "$v" ]; then
        echo "ERROR: missing value for $name"
        exit 1
    fi
done

## validate environment
archcount=`echo $ARCHS | awk '{ print NF }'`
if [ "$archcount" -ne 1 ]; then
    echo "*********************************************************************"
    echo "***"
    echo "*** ERROR: multiple architectures: $ARCHS"
    echo "***"
    echo "*** This build system does not support more than one (1)"
    echo "*** simultaneous architecture setting."
    echo "***"
    echo "*********************************************************************"
    exit 1
fi

exit_post_log=0

## compute goals; these correlate with TARGET_NAME and ACTION from Xcode
spec="$TARGET_NAME:$ACTION"
echo "target specification: $spec"
case "$spec" in
    external:clean)
        if [ "$EXTERNAL_DRIVER" == "xcode" ]; then
            ## driving build from Xcode.app do pristine clean
            if [ -z "$EXTERNAL_BUILD" ]; then
                echo "ERROR: unsafe rm -fr would result because EXTERNAL_BUILD is not defined"
                exit 1
            fi
            if [ -d "$EXTERNAL_BUILD" ]; then
                cmd="/bin/rm -fr $EXTERNAL_BUILD/*"
                echo "$cmd"
                $cmd
                [ $? -ne 0 ] && exit 1
                exit_post_log=1
            else
                echo "already clean"
            fi
        else
            ## driving build from xcodebuild do xclean, preserving configuration
            goals=xclean
        fi
        ;;
    external:*)
        if [ -z "$EXTERNAL_GOALS" ]; then
            goals=build
        else
            goals="$EXTERNAL_GOALS"
        fi
        ;;
    *)
        echo "ERROR: unexpected env specification: $spec"
        exit 1
        ;;
esac

## compute if re/configure necessary
if [ ! -f "$EXTERNAL_BUILD/GNUmakefile" ]; then
    reconfigure="no configuration present"
elif [ "$EXTERNAL_SRC/make/configure.py" -nt "$EXTERNAL_BUILD/GNUmakefile" ]; then
    reconfigure="configure script was updated"
elif [ "$EXTERNAL_DRIVER" == "bootstrap" ]; then
    reconfigure="driver bootstrap"
elif [[ "${PATH}" == "${DEVELOPER_BIN_DIR%/bin}"* ]] ||
     [[ "${PATH}" == "${DT_TOOLCHAIN_DIR%/bin}"* ]]  ||
     [[ "${PATH}" == "${PLATFORM_DIR%/bin}"* ]]      ||
     [[ "${PATH}" == "${PLATFORM_DEVELOPER_BIN_DIR%/bin}"* ]] ||
     [[ "${PATH}" == "${SYSTEM_DEVELOPER_BIN_DIR%/bin}"*   ]]; then
    reconfigure="unclobber PATH"
else
    reconfigure=
fi

## perform re/configure
if [ -n "$reconfigure" ]; then
    echo "reconfiguring ($reconfigure)"

    ## respect PATH priority
    OIFS="${IFS}"
    IFS=':'
    read -r -a PATH_ITEMS <<< "${PATH}"
    IFS="${OIFS}"
    PATH=""
    APPLE_PATH=""
    for ITEM in "${PATH_ITEMS[@]}"; do
        if [[ "${ITEM}" == "${DEVELOPER_BIN_DIR%/bin}"* ]] ||
           [[ "${ITEM}" == "${DT_TOOLCHAIN_DIR%/bin}"* ]]  ||
           [[ "${ITEM}" == "${PLATFORM_DIR%/bin}"* ]]      ||
           [[ "${ITEM}" == "${PLATFORM_DEVELOPER_BIN_DIR%/bin}"* ]] ||
           [[ "${ITEM}" == "${SYSTEM_DEVELOPER_BIN_DIR%/bin}"*   ]]; then
            APPLE_PATH="${APPLE_PATH}:${ITEM}"
        else
            PATH="${PATH}:${ITEM}"
        fi
    done
    PATH="${PATH}${APPLE_PATH}"
    export PATH="${PATH:1}"
    echo "Unclobbering PATH:"
    echo "    export PATH=\"${PATH}\""

    if [ "$EXTERNAL_DRIVER" == "bootstrap" ]; then
        driver="--xcode-driver=terminal"
    else
        driver="--xcode-driver=$EXTERNAL_DRIVER"
    fi

    ## determine which compiler to use based on Xcode environment (project).
    case "$GCC_VERSION" in
    com.apple.compilers.llvmgcc42)
        gcc="--gcc=`$DEVELOPER_BIN_DIR/xcodebuild -find-executable llvm-gcc-4.2`"
        ;;
    com.apple.compilers.llvm.clang.1_0)
        gcc="--gcc=`$DEVELOPER_BIN_DIR/xcodebuild -find-executable clang`"
        ;;
    *)
        echo "*********************************************************************"
        echo "***"
        echo "*** ERROR: unexpected value for GCC_VERSION: $GCC_VERSION"
        echo "***"
        echo "*********************************************************************"
        exit 1
        ;;
    esac

    if [ -n "$ARCHS" ]; then
        arch="--arch=$ARCHS"
    else
        arch=
    fi

    case "$CONFIGURATION" in
    debug*)
        debug="--debug=std --optimize=none"
        ;;
    release*|*)
        debug=
        ;;
    esac

    if [ -n "$SDKROOT" ]; then
        sysroot="--sysroot=$SDKROOT"
    else
        sysroot=
    fi

    if [ -n "$MACOSX_DEPLOYMENT_TARGET" ]; then
        minver="--minver=$MACOSX_DEPLOYMENT_TARGET"
    else
        minver=
    fi

    ## pickup user setting from Xcode IDE and avoid recursion
    if [ -n "$EXTERNAL_CONFIGURE" ]; then
        extconf="$EXTERNAL_CONFIGURE"
    else
        extconf=
    fi
    EXTERNAL_CONFIGURE=

    ## invoke configure with (hidden) option which indicates conf performed by xcode
    (set -ex; "$EXTERNAL_SRC/configure" --force \
        $EXTERNAL_CONF_ARGS \
        --build="$EXTERNAL_BUILD" \
        $driver \
        --xcode-symroot="$SYMROOT" \
        --xcode-config="$EXTERNAL_XCCONFIG" \
        $gcc $arch $debug $sysroot $minver $extconf)
    [ $? -ne 0 ] && exit 1
fi

## log environment as provided by Xcode
logdir="$EXTERNAL_BUILD/log"
if [ ! -d "$logdir" ]; then
    mkdir -p "$logdir"
fi
env | sort > "$logdir/xcodemake.env.txt"

[ $exit_post_log -ne 0 ] && exit 0

## safeguard against passing blank value which would result in unlimited jobs
if [ -z "$EXTERNAL_JOBS" ]; then
    jobs=
elif [ "$EXTERNAL_JOBS" == "auto" ]; then
    jobs=--jobs=`sysctl -n hw.activecpu`
else
    jobs=--jobs=$EXTERNAL_JOBS
fi

## when driving from terminal; ensure $SYMROOT/external/ exists relative to SYMROOT
if [ "$EXTERNAL_DRIVER" == "terminal" -a ! -e "$SYMROOT/external" ]; then
    ln -s "$EXTERNAL_BUILD" "$SYMROOT/external"
fi

## pull the trigger
## must set XCODE.driver to prevent infinite recursion
set -x
exec make -C "$EXTERNAL_BUILD" XCODE.driver=xcodemake $jobs $goals $EXTERNAL_VARS