33
33
# the build directory, but an external directory can be specified using the
34
34
# --build-env-dir option. The build environment directory can be shared by any
35
35
# number of build directories, independently of target / tool chain.
36
- #
37
- # Project options can be passed in the usual GNU configure style (--enable-foo,
38
- # --foo-bar=value) and are translated into GN build arguments. By default,
39
- # configure will override the toolchain for the GN build using a 'custom'
40
- # toolchain assembled from the usual environment variables (CC, CXX, AR, CFLAGS,
41
- # CXXFLAGS, ...).
42
36
43
- function usage() {
37
+ set -o pipefail
38
+ shopt -s extglob
39
+
40
+ function usage() { # status
44
41
info " Usage: $0 [OPTIONS] [--project=... [PROJECT OPTIONS]]"
45
42
info " Options:"
46
- info " --build-env-dir=DIR Directory to create (host) build environment in"
47
- info " --project=DIR Sub-directory to build, e.g. examples/lighting-app/linux"
48
- exit 0
43
+ info " --build-env-dir=DIR Directory to create (host) build environment in"
44
+ info " --project=DIR Sub-directory to build, eg examples/lighting-app/linux"
45
+ info " "
46
+ info " Project options (mapped to GN build args):"
47
+ info " --enable-<ARG>[=no] Enables (or disables with '=no') a bool build arg"
48
+ info " --<ARG>=<VALUE> Sets a (non-bool) build arg to the given value"
49
+ info " GN argument names can be specified with '-' instead of '_' and prefixes"
50
+ info " like 'chip_' can be ommitted from names. For the full list of available"
51
+ info " build arguments, see the generated args.configured file."
52
+ info " "
53
+ info " By default, the toolchain for the GN build will be configured from the usual"
54
+ info " environment variables (CC, CXX, AR, CFLAGS, CXXFLAGS, ...), falling back to"
55
+ info " default tool names (CC=cc, ...). When using this script within an external"
56
+ info " build system, toolchain environment variables should be populated."
57
+ exit " $1 "
49
58
}
50
59
51
60
function main() { # ...
52
- set -o pipefail
53
61
CHIP_ROOT=$( cd " $( dirname " $0 " ) /.." && pwd)
54
62
BUILD_ENV_DEPS=(
55
63
" ${CHIP_ROOT} /scripts/setup/requirements.build.txt"
56
64
" ${CHIP_ROOT} /scripts/setup/constraints.txt"
57
65
" ${CHIP_ROOT} /scripts/setup/zap.version"
58
66
)
59
67
60
- if [[ " $PWD " == " $CHIP_ROOT " ]]; then
61
- BUILD_DIR=" out/configured"
62
- BUILD_ROOT=" ${CHIP_ROOT} /${BUILD_DIR} "
63
- BUILD_ENV_DIR=" .venv"
64
- info " Configuring in-tree, will build in $BUILD_DIR using environment $BUILD_ENV_DIR "
65
- else
66
- BUILD_DIR=" ."
67
- BUILD_ROOT=" $PWD "
68
- BUILD_ENV_DIR=" build-env"
69
- fi
68
+ # Parse global options, process VAR=VALUE style arguments, and collect project options
69
+ BUILD_ENV_DIR=
70
70
PROJECT=
71
-
72
- # Parse main options but leave project options in $@
73
- while [[ $# -gt 0 && -z " $PROJECT " ]]; do
71
+ PROJECT_ARGS=()
72
+ while [[ $# -gt 0 ]]; do
74
73
case " $1 " in
75
- --help) usage ;;
74
+ --help) usage 0 ;;
76
75
--build-env-dir=* ) BUILD_ENV_DIR=" ${1#* =} " ;;
77
76
--project=* ) PROJECT=" ${1#* =} " ;;
78
- * ) fail " Invalid argument: '$1 '" ;;
77
+ + ([A-Z_])=* ) export " $1 " ;;
78
+ * )
79
+ [[ -n " $PROJECT " ]] || fail " Invalid argument: '$1 '"
80
+ PROJECT_ARGS+=(" $1 " )
81
+ ;;
79
82
esac
80
83
shift
81
84
done
82
85
86
+ # Ensure we have something to do
87
+ [[ -n " $PROJECT " || -n " $BUILD_ENV_DIR " ]] || usage 1
88
+
83
89
if [[ -n " $PROJECT " ]]; then
84
90
local subdir=" $( cd " ${CHIP_ROOT} /${PROJECT} " 2> /dev/null && pwd) "
85
91
[[ -n " $subdir " && -r " ${subdir} /.gn" ]] || fail " Invalid project '${PROJECT} '"
@@ -89,7 +95,28 @@ function main() { # ...
89
95
90
96
check_binary gn GN
91
97
check_binary ninja NINJA
92
- if ! activate_build_env; then
98
+
99
+ # Work out build and environment directories
100
+ if [[ " $PWD " == " $CHIP_ROOT " ]]; then
101
+ BUILD_DIR=" out/configured"
102
+ NINJA_HINT=" ninja -C ${BUILD_DIR} "
103
+ else
104
+ BUILD_DIR=" ."
105
+ NINJA_HINT=" ninja"
106
+ fi
107
+
108
+ if [[ -n " $BUILD_ENV_DIR " ]]; then
109
+ mkdir -p " $BUILD_ENV_DIR "
110
+ BUILD_ENV_PATH=" $( cd " $BUILD_ENV_DIR " && pwd) "
111
+ [[ -n " $BUILD_ENV_PATH " ]] || fail " Invalid build-env-dir '${BUILD_ENV_DIR} '"
112
+ BUILD_ENV_DIR=" $BUILD_ENV_PATH " # absolute
113
+ else
114
+ BUILD_ENV_DIR=" build-env" # relative to BUILD_DIR
115
+ BUILD_ENV_PATH=" ${BUILD_DIR} /${BUILD_ENV_DIR} "
116
+ fi
117
+
118
+ # Create the build environment if necessary
119
+ if ! check_build_env; then
93
120
check_python
94
121
configure_python_env
95
122
if ! check_binary zap-cli; then
@@ -98,15 +125,19 @@ function main() { # ...
98
125
finalize_build_env
99
126
fi
100
127
128
+ # Configure the project (if requested)
101
129
if [[ -z " $PROJECT " ]]; then
102
130
info " Build environment created. (Specify --project=DIR to configure a build.)"
103
131
return
104
132
fi
105
133
134
+ [[ " $BUILD_DIR " != " ." ]] && info " Configuring in-tree, will build in ${BUILD_DIR} "
135
+
106
136
create_empty_pw_env
107
- gn_generate " $@ "
137
+ guess_toolchain
138
+ gn_generate " ${PROJECT_ARGS[@]} "
108
139
create_ninja_wrapper
109
- info " You can now run ./ninja-build"
140
+ info " You can now run ./ninja-build (or $NINJA_HINT ) "
110
141
}
111
142
112
143
function create_empty_pw_env() {
@@ -123,61 +154,90 @@ function create_empty_pw_env() {
123
154
fi
124
155
}
125
156
157
+ function guess_toolchain() {
158
+ # There is no widely used standard command for the C++ compiler (analogous to
159
+ # `cc` for the C compiler), so if neither CC nor CXX are defined try to guess.
160
+ if [[ -z " $CC " && -z " $CXX " ]] && have_binary cc; then
161
+ local probe=" $( cc -E - <<< ' gnu=__GNUC__ clang=__clang__' 2> /dev/null) "
162
+ # Check for clang first because it also defines __GNUC__
163
+ if [[ " $probe " =~ clang= [1-9] ]] && have_binary clang && have_binary clang++; then
164
+ info " Guessing CC=clang CXX=clang++ because cc appears to be clang"
165
+ export CC=clang CXX=clang++
166
+ elif [[ " $probe " =~ gnu= [1-9] ]] && have_binary gcc && have_binary g++; then
167
+ info " Guessing CC=gcc CXX=g++ because cc appears to be gcc"
168
+ export CC=gcc CXX=g++
169
+ else
170
+ info " Unable to guess c++ compiler: $probe "
171
+ fi
172
+ fi
173
+ }
174
+
126
175
function gn_generate() { # [project options]
127
- mkdir -p " ${BUILD_ROOT} "
128
- ensure_no_clobber " ${BUILD_ROOT} /args.gn"
129
- (
130
- cd " ${CHIP_ROOT} /${PROJECT} " # --root= doesn't work for gn args!
131
-
132
- # Run gn gen with an empty args.gn first so we can list all arguments
133
- info " Configuring gn build arguments (see $BUILD_DIR /args.configured for full list)"
134
- echo " # ${CONFIGURE_MARKER} " > " ${BUILD_ROOT} /args.gn"
135
- gn -q gen " $BUILD_ROOT "
136
-
137
- # Use the argument list to drive the mapping of our command line options to GN args
138
- call_impl process_project_args <( gn args " $BUILD_ROOT " --list --json) " $@ " >> " ${BUILD_ROOT} /args.gn"
139
- gn args " $BUILD_ROOT " --list > " ${BUILD_ROOT} /args.configured"
140
-
141
- # Now gn gen with the arguments we have configured.
142
- info " Running gn gen to generate ninja files"
143
- gn -q gen " $BUILD_ROOT "
144
- )
176
+ mkdir -p " ${BUILD_DIR} "
177
+ ensure_no_clobber " ${BUILD_DIR} /args.gn"
178
+
179
+ # Pass --script-executable to all `gn` calls so scripts run in our venv
180
+ local gn=(gn --script-executable=" ${BUILD_ENV_DIR} /bin/python" --root=" ${CHIP_ROOT} /${PROJECT} " )
181
+
182
+ # Run gn gen with an empty args.gn first so we can list all arguments
183
+ info " Configuring gn build arguments (see $BUILD_DIR /args.configured for full list)"
184
+ {
185
+ echo " # ${CONFIGURE_MARKER} "
186
+ echo " # project root: ${PROJECT} "
187
+ } > " ${BUILD_DIR} /args.gn"
188
+ " ${gn[@]} " -q gen " $BUILD_DIR "
189
+
190
+ # Use the argument list to drive the mapping of our command line options to GN args
191
+ call_impl process_project_args <( " ${gn[@]} " args " $BUILD_DIR " --list --json) " $@ " >> " ${BUILD_DIR} /args.gn"
192
+ " ${gn[@]} " args " $BUILD_DIR " --list > " ${BUILD_DIR} /args.configured"
193
+
194
+ # Now gn gen with the arguments we have configured.
195
+ info " Running gn gen to generate ninja files"
196
+ " ${gn[@]} " -q gen " $BUILD_DIR "
145
197
}
146
198
147
199
function create_ninja_wrapper() {
148
- # Note: "." != $BUILD_DIR for in-tree builds
149
200
local wrapper=" ninja-build"
150
201
ensure_no_clobber " $wrapper "
151
- cat > " $wrapper " << END
152
- #!/bin/bash -e
153
- # ${CONFIGURE_MARKER}
154
- cd "\$ (dirname "\$ 0")"
155
- source "${BUILD_ENV_DIR} /bin/activate"
156
- exec "${NINJA} " -C "${BUILD_DIR} " "\$ @"
157
- END
202
+ {
203
+ echo " #!/bin/bash -e"
204
+ echo " # ${CONFIGURE_MARKER} "
205
+ if [[ " $BUILD_DIR " != " ." ]]; then
206
+ echo ' args=(-C "$(dirname "$0")/' " ${BUILD_DIR} " ' ")'
207
+ else
208
+ echo ' args=() dir="$(dirname "$0")"'
209
+ echo ' [[ "$dir" != "." ]] && args=(-C "$dir")'
210
+ fi
211
+ echo ' exec ninja "${args[@]}" "$@"'
212
+ } > " $wrapper "
158
213
chmod a+x " $wrapper "
159
214
}
160
215
161
- function activate_build_env () {
216
+ function check_build_env () {
162
217
generate_build_env_cksum # re-used by finalize_build_env
163
- [[ -r " ${BUILD_ENV_DIR } /.cksum" ]] || return 1
164
- read -r < " ${BUILD_ENV_DIR } /.cksum" || true
218
+ [[ -r " ${BUILD_ENV_PATH } /.cksum" ]] || return 1
219
+ read -r < " ${BUILD_ENV_PATH } /.cksum" || true
165
220
[[ " $REPLY " == " $CURRENT_ENV_CKSUM " ]] || return 1
166
221
167
- [[ -r " ${BUILD_ENV_DIR} /bin/activate" ]] || return 1
168
- info " Using existing build environment: ${BUILD_ENV_DIR} "
169
- source " ${BUILD_ENV_DIR} /bin/activate"
170
- PYTHON=" python"
222
+ [[ -r " ${BUILD_ENV_PATH} /bin/activate" ]] || return 1
223
+ info " Using existing build environment: ${BUILD_ENV_PATH} "
224
+ PYTHON=" ${BUILD_ENV_PATH} /bin/python"
171
225
}
172
226
173
227
function configure_python_env() {
174
228
progress " Setting up Python venv"
175
- " $PYTHON " -m venv " $BUILD_ENV_DIR "
176
- info " ok"
229
+ " $PYTHON " -m venv --clear " $BUILD_ENV_PATH "
230
+ info " $BUILD_ENV_PATH "
231
+
232
+ # Install our auto-loading venvactivate module so that running scripts via
233
+ # the venv python has the side-effect of fully activating the environment.
234
+ local sitepkgs=(" ${BUILD_ENV_PATH} /lib/python" * " /site-packages" )
235
+ [[ -d " $sitepkgs " ]] || fail " Failed to locate venv site-packages"
236
+ cp " ${CHIP_ROOT} /scripts/configure.venv/venvactivate" .{pth,py} " ${sitepkgs} /"
177
237
178
238
progress " Installing Python build dependencies"
179
- " ${BUILD_ENV_DIR } /bin/pip" install --require-virtualenv --quiet --upgrade pip wheel
180
- " ${BUILD_ENV_DIR } /bin/pip" install --require-virtualenv --quiet \
239
+ " ${BUILD_ENV_PATH } /bin/pip" install --require-virtualenv --quiet --upgrade pip wheel
240
+ " ${BUILD_ENV_PATH } /bin/pip" install --require-virtualenv --quiet \
181
241
-r " ${CHIP_ROOT} /scripts/setup/requirements.build.txt" \
182
242
-c " ${CHIP_ROOT} /scripts/setup/constraints.txt"
183
243
info " ok"
@@ -190,9 +250,7 @@ function generate_build_env_cksum() {
190
250
}
191
251
192
252
function finalize_build_env() {
193
- echo " $CURRENT_ENV_CKSUM " > " ${BUILD_ENV_DIR} /.cksum"
194
- source " ${BUILD_ENV_DIR} /bin/activate"
195
- PYTHON=" python"
253
+ echo " $CURRENT_ENV_CKSUM " > " ${BUILD_ENV_PATH} /.cksum"
196
254
}
197
255
198
256
function download_zap() {
@@ -206,8 +264,8 @@ function download_zap() {
206
264
local url=" https://github.com/project-chip/zap/releases/download/${version} /zap-${platform} .zip"
207
265
208
266
progress " Installing zap-cli from $url "
209
- call_impl download_and_extract_zip " $url " " ${BUILD_ENV_DIR } /bin" zap-cli
210
- chmod a+x " ${BUILD_ENV_DIR } /bin/zap-cli" # ZipFile.extract() does not handle permissions
267
+ call_impl download_and_extract_zip " $url " " ${BUILD_ENV_PATH } /bin" zap-cli
268
+ chmod a+x " ${BUILD_ENV_PATH } /bin/zap-cli" # ZipFile.extract() does not handle permissions
211
269
info " ok"
212
270
}
213
271
0 commit comments