blob: eed3bc5e1dd06cc19e5e5e8b1e40f6aa8ac71f28 [file] [log] [blame]
Wyatt Heplerf9fb90f2020-09-30 18:59:33 -07001.. _module-pw_env_setup:
Rob Mohrd45e2342020-03-03 15:02:18 -08002
3------------
4pw_env_setup
5------------
6A classic problem in the embedded space is reducing the time from git clone
7to having a binary executing on a device. The issue is that an entire suite
8of tools is needed for non-trivial production embedded projects. For example:
9
10 - A C++ compiler for your target device, and also for your host
11 - A build system or three; for example, GN, Ninja, CMake, Bazel
12 - A code formatting program like clang-format
13 - A debugger like OpenOCD to flash and debug your embedded device
14 - A known Python version with known modules installed for scripting
15 - A Go compiler for the Go-based command line tools
16
17...and so on
18
19In the server space, container solutions like Docker or Podman solve this;
20however, in our experience container solutions are a mixed bag for embedded
21systems development where one frequently needs access to native system
22resources like USB devices, or must operate on Windows.
23
Armando Montanez0054a9b2020-03-13 13:06:24 -070024``pw_env_setup`` is our compromise solution for this problem that works on Mac,
Rob Mohrd45e2342020-03-03 15:02:18 -080025Windows, and Linux. It leverages the Chrome packaging system `CIPD`_ to
26bootstrap a Python installation, which in turn inflates a virtual
27environment. The tooling is installed into your workspace, and makes no
28changes to your system. This tooling is designed to be reused by any
29project.
30
Rob Mohr55bb0ad2021-05-22 10:59:52 -070031.. _CIPD: https://github.com/luci/luci-go/tree/HEAD/cipd
Rob Mohrfcf60372020-11-04 11:41:36 -080032
Rob Mohr43d36112020-09-09 13:38:13 -070033Users interact with ``pw_env_setup`` with two commands: ``. bootstrap.sh`` and
34``. activate.sh``. The bootstrap command always pulls down the current versions
35of CIPD packages and sets up the Python virtual environment. The activate
36command reinitializes a previously configured environment, and if none is found,
37runs bootstrap.
38
Rob Mohr43d36112020-09-09 13:38:13 -070039.. note::
40 On Windows the scripts used to set up the environment are ``bootstrap.bat``
41 and ``activate.bat``. For simplicity they will be referred to with the ``.sh``
42 endings unless the distinction is relevant.
43
Rob Mohrd45e2342020-03-03 15:02:18 -080044.. warning::
Armando Montanez0054a9b2020-03-13 13:06:24 -070045 At this time ``pw_env_setup`` works for us, but isn’t well tested. We don’t
Rob Mohrd45e2342020-03-03 15:02:18 -080046 suggest relying on it just yet. However, we are interested in experience
47 reports; if you give it a try, please `send us a note`_ about your
48 experience.
49
50.. _send us a note: pigweed@googlegroups.com
Rob Mohrd596a532020-04-03 08:59:12 -070051
Rob Mohr43d36112020-09-09 13:38:13 -070052==================================
53Using pw_env_setup in your project
54==================================
55
Rob Mohr895d3df2020-10-14 08:42:39 -070056Downstream Projects Using Pigweed's Packages
57********************************************
Rob Mohrd596a532020-04-03 08:59:12 -070058
Rob Mohr895d3df2020-10-14 08:42:39 -070059Projects using Pigweed can leverage ``pw_env_setup`` to install Pigweed's
60dependencies or their own dependencies. Projects that only want to use Pigweed's
61dependencies without modifying them can just source Pigweed's ``bootstrap.sh``
62and ``activate.sh`` scripts.
Rob Mohr43d36112020-09-09 13:38:13 -070063
64An example of what your project's `bootstrap.sh` could look like is below. This
65assumes `bootstrap.sh` is at the top level of your repository.
66
67.. code-block:: bash
68
69 # Do not include a "#!" line, this must be sourced and not executed.
70
71 # This assumes the user is sourcing this file from it's parent directory. See
72 # below for a more flexible way to handle this.
73 PROJ_SETUP_SCRIPT_PATH="$(pwd)/bootstrap.sh"
74
Rob Mohrfcf60372020-11-04 11:41:36 -080075 export PW_PROJECT_ROOT="$(_python_abspath "$(dirname "$PROJ_SETUP_SCRIPT_PATH")")"
Rob Mohr43d36112020-09-09 13:38:13 -070076
77 # You may wish to check if the user is attempting to execute this script
78 # instead of sourcing it. See below for an example of how to handle that
79 # situation.
80
Rob Mohrfcf60372020-11-04 11:41:36 -080081 # Source Pigweed's bootstrap utility script.
82 # Using '.' instead of 'source' for POSIX compatibility. Since users don't use
83 # dash directly, using 'source' in most documentation so users don't get
84 # confused and try to `./bootstrap.sh`.
85 . "$PW_PROJECT_ROOT/third_party/pigweed/pw_env_setup/util.sh"
86
87 pw_check_root "$PW_ROOT"
88 _PW_ACTUAL_ENVIRONMENT_ROOT="$(pw_get_env_root)"
89 export _PW_ACTUAL_ENVIRONMENT_ROOT
90 SETUP_SH="$_PW_ACTUAL_ENVIRONMENT_ROOT/activate.sh"
91 pw_bootstrap --args... # See below for details about args.
92 pw_finalize bootstrap "$SETUP_SH"
Rob Mohr43d36112020-09-09 13:38:13 -070093
Nathaniel Broughe22ac202021-04-16 10:30:37 +080094
95Bazel Usage
96-----------
97It is possible to pull in a CIPD dependency into Bazel using WORKSPACE rules
98rather than using `bootstrap.sh`. e.g.
99
100.. code:: python
101
102 # WORKSPACE
103
104 load(
105 "@pigweed//pw_env_setup/bazel/cipd_setup:cipd_rules.bzl",
106 "cipd_client_repository",
107 "cipd_repository",
108 )
109
110 # Must be called before cipd_repository
111 cipd_client_repository()
112
113 cipd_repository(
114 name = "bloaty",
115 path = "pigweed/third_party/bloaty-embedded/${os=linux,mac}-${arch=amd64}",
116 tag = "git_revision:2d87d204057b419f5290f8d38b61b9c2c5b4fb52-2",
117 )
118
119From here it is possible to get access to the Bloaty binaries using the
120following command.
121
122.. code:: sh
123
124 bazel run @bloaty//:bloaty -- --help
125
Rob Mohr43d36112020-09-09 13:38:13 -0700126User-Friendliness
Rob Mohr895d3df2020-10-14 08:42:39 -0700127-----------------
Rob Mohr43d36112020-09-09 13:38:13 -0700128
129You may wish to allow sourcing `bootstrap.sh` from a different directory. In
130that case you'll need the following at the top of `bootstrap.sh`.
131
132.. code-block:: bash
133
134 _python_abspath () {
135 python -c "import os.path; print(os.path.abspath('$@'))"
136 }
137
138 # Use this code from Pigweed's bootstrap to find the path to this script when
139 # sourced. This should work with common shells. PW_CHECKOUT_ROOT is only used in
140 # presubmit tests with strange setups, and can be omitted if you're not using
141 # Pigweed's automated testing infrastructure.
142 if test -n "$PW_CHECKOUT_ROOT"; then
143 PROJ_SETUP_SCRIPT_PATH="$(_python_abspath "$PW_CHECKOUT_ROOT/bootstrap.sh")"
144 unset PW_CHECKOUT_ROOT
145 # Shell: bash.
146 elif test -n "$BASH"; then
147 PROJ_SETUP_SCRIPT_PATH="$(_python_abspath "$BASH_SOURCE")"
148 # Shell: zsh.
149 elif test -n "$ZSH_NAME"; then
150 PROJ_SETUP_SCRIPT_PATH="$(_python_abspath "${(%):-%N}")"
151 # Shell: dash.
152 elif test ${0##*/} = dash; then
153 PROJ_SETUP_SCRIPT_PATH="$(_python_abspath \
154 "$(lsof -p $$ -Fn0 | tail -1 | sed 's#^[^/]*##;')")"
155 # If everything else fails, try $0. It could work.
156 else
157 PROJ_SETUP_SCRIPT_PATH="$(_python_abspath "$0")"
158 fi
159
160You may also wish to check if the user is attempting to execute `bootstrap.sh`
161instead of sourcing it. Executing `bootstrap.sh` would download everything
162required for the environment, but cannot modify the environment of the parent
163process. To check for this add the following.
164
165.. code-block:: bash
166
167 # Check if this file is being executed or sourced.
168 _pw_sourced=0
169 # If not running in Pigweed's automated testing infrastructure the
170 # SWARMING_BOT_ID check is unnecessary.
171 if [ -n "$SWARMING_BOT_ID" ]; then
172 # If set we're running on swarming and don't need this check.
173 _pw_sourced=1
174 elif [ -n "$ZSH_EVAL_CONTEXT" ]; then
175 case $ZSH_EVAL_CONTEXT in *:file) _pw_sourced=1;; esac
176 elif [ -n "$KSH_VERSION" ]; then
177 [ "$(cd $(dirname -- $0) && pwd -P)/$(basename -- $0)" != \
178 "$(cd $(dirname -- ${.sh.file}) && pwd -P)/$(basename -- ${.sh.file})" ] \
179 && _pw_sourced=1
180 elif [ -n "$BASH_VERSION" ]; then
181 (return 0 2>/dev/null) && _pw_sourced=1
182 else # All other shells: examine $0 for known shell binary filenames
183 # Detects `sh` and `dash`; add additional shell filenames as needed.
184 case ${0##*/} in sh|dash) _pw_sourced=1;; esac
185 fi
186
Rob Mohrfcf60372020-11-04 11:41:36 -0800187 _pw_eval_sourced "$_pw_sourced"
Rob Mohr43d36112020-09-09 13:38:13 -0700188
Rob Mohr895d3df2020-10-14 08:42:39 -0700189Downstream Projects Using Different Packages
190********************************************
191
192Projects depending on Pigweed but using additional or different packages should
Rob Mohrcccd63c2021-02-26 12:03:07 -0800193copy the Pigweed `sample project`'s ``bootstrap.sh`` and ``config.json`` and
194update the call to ``pw_bootstrap``. Search for "downstream" for other places
195that may require changes, like setting the ``PW_ROOT`` and ``PW_PROJECT_ROOT``
196environment variables. Explanations of parts of ``config.json`` are described
197here.
Rob Mohrfcf60372020-11-04 11:41:36 -0800198
Rob Mohr55bb0ad2021-05-22 10:59:52 -0700199.. _sample project: https://pigweed.googlesource.com/pigweed/sample_project/+/HEAD
Rob Mohr895d3df2020-10-14 08:42:39 -0700200
Rob Mohr8507cd82021-06-24 09:50:34 -0700201``root_variable``
202 Variable used to point to the root of the source tree. Optional, can always
203 use ``PW_PROJECT_ROOT`` instead. (That variable will be set regardless of
204 whether this is provided.)
205
Rob Mohrcccd63c2021-02-26 12:03:07 -0800206``cipd_package_files``
Rob Mohr09dc0a32021-05-19 11:48:30 -0700207 CIPD package file. JSON file consisting of a list of dictionaries with "path",
208 "platforms", and "tags" keys. An example is below.
209
210.. code-block:: json
211
212 {
213 "path": "infra/3pp/tools/go/${platform}",
214 "platforms": [
215 "linux-amd64",
216 "linux-arm64",
217 "mac-amd64",
218 "windows-amd64"
219 ],
220 "tags": [
221 "version:2@1.16.3"
222 ]
Ewout van Bekkum653792b2021-05-20 17:35:25 -0700223 }
Rob Mohr895d3df2020-10-14 08:42:39 -0700224
Rob Mohrcccd63c2021-02-26 12:03:07 -0800225``virtualenv.gn_targets``
226 Target for installing Python packages. Downstream projects will need to
227 create targets to install their packages or only use Pigweed Python packages.
Rob Mohr895d3df2020-10-14 08:42:39 -0700228
Rob Mohrcccd63c2021-02-26 12:03:07 -0800229``virtualenv.gn_root``
230 The root directory of your GN build tree, relative to ``PW_PROJECT_ROOT``.
231 This is the directory your project's ``.gn`` file is located in. If you're
232 only installing Pigweed Python packages, use the location of the Pigweed
233 submodule.
Rob Mohr895d3df2020-10-14 08:42:39 -0700234
Damian Krolik5028f122021-06-15 16:21:41 +0200235``virtualenv.system_packages``
236 A boolean value that can be used the give the Python virtual environment
237 access to the system site packages. Defaults to ``false``.
238
Rob Mohr32b36292021-06-18 10:55:05 -0700239``optional_submodules``
240 By default environment setup will check that all submodules are present in
241 the checkout. Any submodules in this list are excluded from that check.
242
Rob Mohrcccd63c2021-02-26 12:03:07 -0800243An example of a config file is below.
Rob Mohr895d3df2020-10-14 08:42:39 -0700244
Rob Mohrcccd63c2021-02-26 12:03:07 -0800245.. code-block:: json
Rob Mohr895d3df2020-10-14 08:42:39 -0700246
Rob Mohrcccd63c2021-02-26 12:03:07 -0800247 {
Rob Mohr8507cd82021-06-24 09:50:34 -0700248 "root_variable": "EXAMPLE_ROOT",
Rob Mohrcccd63c2021-02-26 12:03:07 -0800249 "cipd_package_files": [
250 "pigweed/pw_env_setup/py/pw_env_setup/cipd_setup/pigweed.json",
251 "pigweed/pw_env_setup/py/pw_env_setup/cipd_setup/luci.json"
Rob Mohr04645602021-03-03 11:26:05 -0800252 "tools/myprojectname.json"
Rob Mohrcccd63c2021-02-26 12:03:07 -0800253 ],
254 "virtualenv": {
255 "gn_root": ".",
256 "gn_targets": [
257 ":python.install",
Damian Krolik5028f122021-06-15 16:21:41 +0200258 ],
259 "system_packages": false
Rob Mohr32b36292021-06-18 10:55:05 -0700260 },
261 "optional_submodules": [
262 "optional/submodule/one",
263 "optional/submodule/two"
264 ]
Rob Mohrcccd63c2021-02-26 12:03:07 -0800265 }
Rob Mohr895d3df2020-10-14 08:42:39 -0700266
Rob Mohr04645602021-03-03 11:26:05 -0800267In case the CIPD packages need to be referenced from other scripts, variables
268like ``PW_${BASENAME}_CIPD_INSTALL_DIR`` point to the CIPD install directories,
269where ``${BASENAME}`` is "PIGWEED" for
270"pigweed/pw_env_setup/py/pw_env_setup/cipd_setup/pigweed.json" and "LUCI" for
271"pigweed/pw_env_setup/py/pw_env_setup/cipd_setup/luci.json". This example would
272set the following environment variables.
273
274 - ``PW_LUCI_CIPD_INSTALL_DIR``
275 - ``PW_MYPROJECTNAME_CIPD_INSTALL_DIR``
276 - ``PW_PIGWEED_CIPD_INSTALL_DIR``
277
Rob Mohr9891ced2021-01-13 07:49:28 -0800278Environment Variables
279*********************
280The following environment variables affect env setup behavior. Most users will
281never need to set these.
282
283``CIPD_CACHE_DIR``
284 Location of CIPD cache dir. Defaults to ``$HOME/.cipd-cache-dir``.
285
286``PW_ACTIVATE_SKIP_CHECKS``
287 If set, skip running ``pw doctor`` at end of bootstrap/activate. Intended to
288 be used by automated tools but not interactively.
289
290``PW_BOOTSTRAP_PYTHON``
291 Python executable to be used, for example "python2" or "python3". Defaults to
292 "python".
293
294``PW_ENVIRONMENT_ROOT``
295 Location to which packages are installed. Defaults to ``.environment`` folder
296 within the checkout root.
297
298``PW_ENVSETUP_DISABLE_SPINNER``
299 Disable the spinner during env setup. Intended to be used when the output is
300 being redirected to a log.
301
302``PW_ENVSETUP_QUIET``
303 Disables all non-error output.
Rob Mohre9d5aac2021-01-05 13:12:10 -0800304
Rob Mohr1d2ffdf2021-05-12 14:44:45 -0700305Non-Shell Environments
306**********************
307If using this outside of bash—for example directly from an IDE or CI
308system—users can process the ``actions.json`` file that's generated in the
309environment directory. It lists variables to set, clear, and modify. An
310example ``actions.json`` is shown below. The "append" and "prepend" actions
311are listed in the order they should be applied, so the
312``<pigweed-root>/out/host/host_tools`` entry should be at the beginning of
313``PATH`` and not in the middle somewhere.
314
315.. code-block:: json
316
317 {
318 "modify": {
319 "PATH": {
320 "append": [],
321 "prepend": [
322 "<pigweed-root>/.environment/cipd",
323 "<pigweed-root>/.environment/cipd/pigweed",
324 "<pigweed-root>/.environment/cipd/pigweed/bin",
325 "<pigweed-root>/.environment/cipd/luci",
326 "<pigweed-root>/.environment/cipd/luci/bin",
327 "<pigweed-root>/.environment/pigweed-venv/bin",
328 "<pigweed-root>/out/host/host_tools"
329 ],
330 "remove": []
331 }
332 },
333 "set": {
334 "PW_PROJECT_ROOT": "<pigweed-root>",
335 "PW_ROOT": "<pigweed-root>",
336 "_PW_ACTUAL_ENVIRONMENT_ROOT": "<pigweed-root>/.environment",
337 "PW_CIPD_INSTALL_DIR": "<pigweed-root>/.environment/cipd",
338 "CIPD_CACHE_DIR": "/usr/local/google/home/mohrr/.cipd-cache-dir",
339 "PW_PIGWEED_CIPD_INSTALL_DIR": "<pigweed-root>/.environment/cipd/pigweed",
340 "PW_LUCI_CIPD_INSTALL_DIR": "<pigweed-root>/.environment/cipd/luci",
341 "VIRTUAL_ENV": "<pigweed-root>/.environment/pigweed-venv",
342 "PYTHONHOME": null,
343 "__PYVENV_LAUNCHER__": null
344 }
345 }
346
Rob Mohr43d36112020-09-09 13:38:13 -0700347Implementation
348**************
349
350The environment is set up by installing CIPD and Python packages in
351``PW_ENVIRONMENT_ROOT`` or ``<checkout>/.environment``, and saving modifications
352to environment variables in setup scripts in those directories. To support
353multiple operating systems this is done in an operating system-agnostic manner
354and then written into operating system-specific files to be sourced now and in
355the future when running ``activate.sh`` instead of ``bootstrap.sh``. In the
356future these could be extended to C shell and PowerShell. A logical mapping of
357high-level commands to system-specific initialization files is shown below.
358
359.. image:: doc_resources/pw_env_setup_output.png
360 :alt: Mapping of high-level commands to system-specific commands.
361 :align: left