summaryrefslogtreecommitdiff
path: root/scripts/otp_build_check
blob: ee6e656cdfdb0f7ec19dfcb01fb9b7e71551b154 (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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
#!/bin/sh
#
# %CopyrightBegin%
#
# Copyright Ericsson AB 2023. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# %CopyrightEnd%
#

#
# Performs a lot of (but not always all) build checking that you want to do...
#

docs=yes
dialyzer=yes
tests=all
opt_only=no
format_check=yes

have_printf=no

print_error() {
    if [ $have_printf = yes ]; then
	printf "\033[31mERROR: %s\033[0m\n" "$1" 1>&2
    else
	echo "ERROR: $1" 1>&2
    fi
}

progress() {
    if [ $have_printf = yes ]; then
	printf "\n\033[33m*** %s ***\033[0m\n\n" "$1" 1>&2
    else
	echo "\n*** $1 ***\n" 1>&2
    fi
}

print_usage() {
    cat <<EOF
Usage:
  otp_build check [--help|-h] [--only-opt|-o] [--no-docs|-d] \\
                  [--no-dialyzer|-y] [--no-tests|-n] [--no-format-check|-f] \\
                  [--tests|-t <App0> ... <AppN>]


By default all currently implemented checks will be performed. If any of the
currently used tools are missing, checking will fail. If libraries or tools
needed to support certain conditional features are missing, those features
will not be checked.

If any of these checks do not pass, the code is *not* ready for testing in OTP
daily builds. Note that this script does not check all requirements for testing
in OTP daily builds. These checks are the bare minimum for even considering
testing in OTP daily builds. Currently the following will be performed by
default:

 * Build all applications in optimized mode. If configure already has been run,
   it wont be run again.
 * Debug compile C-code in all applications.
 * Format checking of JIT code.
 * Run dialyzer on all applications.
 * Build all documentation.
 * Run xmllint on all documentation.
 * Run html link check on all documentation.
 * Build all test suites.

Certain build checking can be disabled using the following options:
* [--only-opt|-o] - Only build optimized system. No debug, etc.
* [--no-format-check|-f] - No JIT format checking.
* [--no-docs|-d] - No documentation checking.
* [--no-dialyzer|-y] - No dialyzer checking.
* [--no-tests|-n] - No build checking of test suites.
* [--tests|-t <App0> ... <AppN>] - Only build checking of test suites for
  listed applications.

Only disable build checking for parts of the system that you are certain your
changes wont effect. Note that even though you've made no changes in
documentation source files, documentation build is effected by type changes
in code.

Environment variables used:
* CONFIG_FLAGS - Arguments to pass to configure if it is executed.

Build results will be placed under the \$ERL_TOP/release/<TARGET> directory

EOF
}

usage () {
    print_error "$1"
    print_usage >&2
    exit 1
}

fail () {
    print_error "$1"
    exit 1
}

type printf >/dev/null 2>&1
if [ $? -eq 0 ]; then
    have_printf=yes
fi

[ "$ERL_TOP" != "" ] || fail "ERL_TOP needs to be set"

cd "$ERL_TOP" 2>&1 >/dev/null || {
    fail "Failed to change directory into $ERL_TOP"
}

[ -f "$ERL_TOP/OTP_VERSION" ] || fail "ERL_TOP not valid"

while [ $# -gt 0 ]; do
    case $1 in
        --help|-h)
            print_usage
            exit 0;;
        --only-opt|-o)
            opt_only=yes;;
        --no-docs|-d)
            docs=no;;
        --no-dialyzer|-y)
            dialyzer=no;;
        --no-format-check|-f)
            format_check=no;;
        --no-tests|-n)
            tests=none;;
        --tests|-t)
            shift
            while [ $# -gt 0 ]; do
                case $1 in
                    -*)
                        break;;
	            test_server|emulator|system|epmd)
                        ;;
	            *)
                        [ -d "$ERL_TOP/lib/$1/test" ] || {
                            fail "Invalid application: $1"
                        }
                        ;;
                esac
                tapps="$1 $tapps"
                shift
            done
            [ "$tapps" != "" ] || usage "No test apps given"
            tests="$tapps"
            continue;;
        *)
            usage "Invalid option: $1"
    esac
    shift
done

[ -f "$ERL_TOP/make/config.status" ] || {
    ./configure $CONFIG_FLAGS || fail "configure failed"
}

type gmake >/dev/null 2>&1
if [ $? -eq 0 ]; then
    export MAKE="gmake"
else
    type make >/dev/null 2>&1
    if [ $? -eq 0 ]; then
	export MAKE="make"
    fi
fi

target=`$MAKE target_configured` || fail "Failed to determine target directory"

unset TESTROOT
unset RELEASE_ROOT
unset ERL_LIBS
unset OTP_SMALL_BUILD
unset OTP_TINY_BUILD
unset TARGET

progress "Building OTP in $ERL_TOP"
$MAKE || fail "OTP build failed"
progress "Booting optimized runtime"
$ERL_TOP/bin/cerl -eval "erlang:halt()" || {
    fail "Failed to boot runtime"
}

[ $opt_only = yes ] || {
    progress "Building debug OTP in $ERL_TOP"
    $MAKE TYPE=debug || fail "OTP debug build failed"
    progress "Booting debug runtime"
    $ERL_TOP/bin/cerl -debug -eval "erlang:halt()" || {
        fail "Failed to boot debug runtime"
    }
}

[ $format_check = no ] || {
    clang-format --help 2>&1 >/dev/null || {
        fail "clang-format not installed. Use --no-format-check option to skip."
    }

    progress "Checking C & C++ code formatting"
    $MAKE format-check || {
        fail "Failed to format C & C++ code"
    }
}

progress "Releasing OTP"
$MAKE release || fail "Releasing OTP failed"

cd "$ERL_TOP/release/$target" 2>&1 >/dev/null || {
    fail "Failed to change directory into release directory: $ERL_TOP/release/$target"
}

progress "Installing OTP"
./Install -minimal `pwd` || fail "Failed to install release"

progress "Booting optimized installed runtime"
./bin/erl -eval "erlang:halt()" || {
    fail "Failed to boot installed runtime"
}

cd "$ERL_TOP" 2>&1 >/dev/null || {
    fail "Failed to change directory into $ERL_TOP"
}

export PATH="$ERL_TOP/release/$target/bin:$PATH"

[ $docs = no ] || {
    progress "Building OTP documentation"
    $MAKE docs || fail "Building documentation failed"
    progress "Releasing OTP documentation"
    $MAKE release_docs || fail "Releasing documentation failed"
    progress "Running xmllint on OTP documentation"
    $MAKE xmllint || fail "xmllint of documentation failed"
    progress "Running HTML check on OTP documentation"
    ./scripts/otp_html_check "$ERL_TOP/release/$target/" doc/index.html || {
        fail "HTML check of documentation failed"
    }
}

[ $dialyzer = no ] || {
    progress "Running dialyzer on OTP"
    $MAKE dialyzer || fail "Dialyzing OTP failed"
}

[ "$tests" = none ] || {
    test_dir="$ERL_TOP/release/$target/test"
    [ -d "$test_dir" ] || mkdir "$test_dir" 2>&1 >/dev/null || {
        fail "Failed to create $test_dir directory"
    }
    if [ "$tests" = all ]; then
        progress "Releasing all OTP tests"
        ./otp_build tests "$test_dir" || fail "Release of tests failed"
    else
        for tapp in $tests; do
            case $tapp in
	        test_server)
	            tapp_dir="$ERL_TOP/lib/test_server"
	            if [ ! -d "$tapp_dir" ]; then
		        tapp_dir="$ERL_TOP/lib/common_test/test_server"
	            fi
	            ;;
	        emulator) tapp_dir="$ERL_TOP/erts/emulator/test";;
	        system) tapp_dir="$ERL_TOP/erts/test";;
	        epmd) tapp_dir="$ERL_TOP/erts/epmd/test";;
	        *) tapp_dir="$ERL_TOP/lib/$tapp/test";;
            esac
            cd "$tapp_dir" 2>&1 >/dev/null || {
                fail "Failed to change directory into $tapp_dir"
            }
            progress "Releasing $tapp tests"
            $MAKE "TESTROOT=$test_dir" release_tests || {
                fail "Release of $tapp tests failed"
            }
        done

    fi

    cd "$test_dir" 2>&1 >/dev/null || {
        fail "Failed to change directory into $test_dir"
    }

    for dir in *; do

        [ -d "$test_dir/$dir" ] || continue

        progress "Building $dir tests"

        cd "$test_dir/$dir" 2>&1 >/dev/null || {
            fail "Failed to change directory into $test_dir/$dir"
        }

        for mfile in *_data/Makefile.first; do

            [ "$mfile" != '*_data/Makefile.first' ] || continue

            ddir=`dirname $mfile` || fail "dirname on $test_dir/$dir/$mfile failed"

            cd "$test_dir/$dir/$ddir" 2>&1 >/dev/null || {
                fail "Failed to change directory into $test_dir/$dir/$ddir"
            }

            $MAKE -f Makefile.first || {
                fail "Make of $test_dir/$dir/$ddir/Makefile.first failed"
            }

        done

        cd "$test_dir/$dir" 2>&1 >/dev/null || {
            fail "Failed to change directory into $test_dir/$dir"
        }

        if [ -f Emakefile ]; then
            erl -noshell -eval 'case make:all() of error -> erlang:halt(1); _ -> init:stop() end.' || {
                fail "Build of $dir failed"
            }
        else
            erlc -I `erl -noshell -eval 'io:format("~ts",[code:lib_dir(common_test)]),init:stop()'`/include -I . *.erl || {
                fail "Build of $dir failed"
            }
        fi

    done

    cd "$ERL_TOP" 2>&1 >/dev/null || {
        fail "Failed to change directory into $ERL_TOP"
    }
}

if [ $have_printf = yes ]; then
    printf "\n\033[32m*** Success! ***\033[0m\n\n"
else
    echo "\n*** Success! ***\n"
fi
exit 0