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 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
|
# Installing the AWS CLI v2 from source
Proposal | Metadata
---------------- | -------------
**Author** | Kyle Knapp
**Status** | Finalized
**Created** | 24-August-2021
## Abstract
This document proposes an official mechanism to install the AWS CLI v2 from
source along with an official source distribution artifact.
## Motivation
The AWS CLI v2 is available as pre-built executables for macOS,
glibc-based Linux x86_64, glibc-based Linux aarch64, and Windows (64-bit). The AWS CLI v2 is also
available as a Docker image. Generally, these artifacts provide coverage for
most platforms and environments, but they do not satisfy all use cases:
* The desired platform (e.g, [ARM 32-bit](https://github.com/aws/aws-cli/issues/5426))
is not supported by any of the pre-built executables.
* The environment lacks system dependencies that are required for the pre-built
executable. For example, Alpine Linux uses [musl](https://musl.libc.org/),
but the current executables require glibc. This causes the pre-built
executables to not work out of the box for
[Alpine Linux](https://github.com/aws/aws-cli/issues/4685).
* The environment restricts access to resources only needed by the
pre-built executable. For example, on security hardened systems, it does not
give permission to shared memory
[which is needed](https://github.com/aws/aws-cli/issues/5769)
during the bootloading process of the frozen `aws` executable.
* Users want to be able to install the AWS CLI using the package manager
standard to their environment (e.g., `brew`, `yum`, `apt`) instead of having
to download and use a ZIP, PKG, MSI, etc. The software available through
these package managers are typically maintained by upstream distribution
maintainers. When maintainers import software, they build from source to
maintain full control over the code and packages being imported into their
distribution. Therefore, importing a pre-built executable is generally a
[non-starter for distro maintainers](https://github.com/aws/aws-cli/issues/4842).
* Users may want to patch AWS CLI v2 functionality, but in order to use the
patched functionality, it requires building and installing the AWS CLI v2 from
source. This is especially important for community members that want to test
changes they've made to the source prior to proposing/contributing the change in
the upstream GitHub repository.
Full support for installing the AWS CLI v2 from source will unblock these use
cases because users will be able to build and install the AWS CLI v2 for their
particular environment.
### Goals
The approach for installing the AWS CLI v2 from source should satisfy the
following goals:
1. The source installation process maximizes the number of environments the
AWS CLI v2 can be installed on.
2. The source installation process is straightforward and intuitive. It minimizes
the number of cycles required to figure out how to install the AWS CLI from
source.
3. The source installation process is language agnostic. While the AWS CLI v2
requires Python, users should not require experience in Python and Python
tooling to build from source. Furthermore, if the AWS CLI was to be
rewritten in a different programming language, users installing
from source should not have to learn a new set of build and install steps
and should be able to stay largely unaware of the change other
than possibly needing to install a new dependency.
### Non-goals
While this proposal helps distribution maintainers make the
AWS CLI v2 available through standard package managers, it does not address
adding official support for installing the AWS CLI v2 through them.
It is focused on providing a mechanism for users that want or need
to install the AWS CLI v2 from source.
## Specification
This section defines:
* [The interface for installing from source](#source-buildinstall-interface)
* [The build and install mechanics when installing from source](#buildinstall-mechanics)
* [The details of a hosted source distribution artifact](#hosted-source-distribution)
* [Provisional support for packaging AWS CLI v2 according to PEP517](#provisional-support-for-pep-517)
### Source build/install interface
The AWS CLI v2 leverages [GNU Autotools](https://www.gnu.org/software/automake/faq/autotools-faq.html)
to install from source. In the simplest case, the AWS CLI v2 can be installed
from source by running the following commands from the root of the repository:
```bash
./configure
make
make install
```
These commands are specific to Autotools where:
* `./configure` - Checks the system for all required dependencies and
generates a `Makefile` for building and installing the AWS CLI v2 based on
detected and explicitly specified configurations. See the
[Configuration section](#configuration) for the available configuration
options.
* `make` - Builds the AWS CLI v2. For details on the build mechanics,
see the [Build/install mechanics section](#buildinstall-mechanics).
* `make install` - Installs the built AWS CLI v2 to the configured location
on the system. For details on the install mechanics, see the
[Build/install mechanics section](#buildinstall-mechanics).
After the above commands complete, the AWS CLI v2 is installed at the default
location of `/usr/local/lib/aws-cli` and creates symlinks for the `aws` and
`aws_completer` executables in the `/usr/local/bin` directory. These
locations are configurable through Autotools. See the
[Install location configuration section](#install-location) for more
information.
#### Requirements
These are the requirements to build the AWS CLI v2 from source:
* An environment that can run Autotools generated files (e.g.,
`configure`, `Makefile`). These files are widely portable across POSIX
platforms, and for systems that do not come with POSIX-compliant shells like
Windows, there is additional software available (e.g., MSYS2) that allow users
to run Autotools generated files. For more information, see the
[Appendix on Windows usage](#windows).
* Python 3.8+ interpreter. The minimum Python version required will increase
over time and follow the same timelines as the [official Python support policy
for AWS SDKs and Tools](https://aws.amazon.com/blogs/developer/python-support-policy-updates-for-aws-sdks-and-tools/)
where an interpreter will only continue to be supported 6 months after its end-of-support date. For example,
Python 3.8 reaches end of support in October 2024, and thus in April 2025, Python 3.8 will no longer be supported
for installing the AWS CLI v2 from source and instead require a Python 3.9+ interpreter.
* (Optional) All build and runtime Python library dependencies
of the AWS CLI v2. This can be opted out of through configuration that
downloads and uses the dependencies as part of the build step.
See the [Downloading dependencies configuration section](#downloading-dependencies)
for more information.
#### Configuration
Configuration for the build and install of the AWS CLI v2 is specified using
the `configure` script. For the documentation of all configuration options, run
the `configure` script with the `--help` option:
```bash
./configure --help
```
This is a sample output from the help page:
```
✗ ./configure -h
Configures builds and installs of the AWS CLI
Usage: ./configure [OPTION]... [ENV_VAR=VALUE]...
Help options:
-h, --help Display help
-V, --version Display version
Installation directories:
--prefix=PREFIX Set installation prefix. By default, this value is
"/usr/local".
--libdir=LIBDIR Set parent directory for AWS CLI installation. The
full path to the AWS CLI installation is "LIBDIR/aws-cli".
The default value for "LIBDIR" is "PREFIX/lib"
(i.e., "/usr/local/lib" if "--prefix" is not set).
--bindir=BINDIR Set install directory for AWS CLI executables. The
default value for "BINDIR" is "PREFIX/bin"
(i.e., "/usr/local/bin" if "--prefix" is not set).
Optional arguments:
--with-install-type=system-sandbox|portable-exe
Specify type of AWS CLI installation. Options are:
"portable-exe", "system-sandbox" (default is
"system-sandbox")
--with-download-deps Download all dependencies and use those when
building the AWS CLI. If not specified, the
dependencies (including all python packages) must be
installed on your system
Some influential environment variables:
PYTHON the Python interpreter
```
The sections below describes the most pertinent options.
##### Install location
Source installation of the AWS CLI v2 uses two configurable directories to
install the AWS CLI v2:
* `libdir` - Parent directory where the AWS CLI v2 will be installed. The
path to the AWS CLI v2 installation is `<libdir-value>/aws-cli`. The default
`libdir` value is `/usr/local/lib` making the default installation directory
`/usr/local/lib/aws-cli`
* `bindir` - Directory where the AWS CLI v2 executables
(e.g., `aws`, `aws_completer`) will be installed. The default location is
`/usr/local/bin`.
The following `configure` options are offered to control the directories used:
* `--prefix` - Sets the directory prefix to use for the installation. The
default value is `/usr/local`.
* `--libdir` - Sets the `libdir` to use for installing the AWS CLI v2. The
default value is `<prefix-value>/lib` (i.e., `/usr/local/lib/` if
`--prefix` is not specified).
* `--bindir` - Sets the `bindir` to use for installing the AWS CLI v2
executables. The default value is `<prefix-value>/bin`
(i.e., `/usr/local/bin/` if both `--prefix` is not specified).
For example, users can use the `--prefix` option to do a user install of the
AWS CLI:
```
./configure --prefix=$HOME/.local
```
This command results in the AWS CLI v2 being installed at
`$HOME/.local/lib/aws-cli` and its executables located in `$HOME/.local/bin`
Users can also use more granular options such as the `--libdir` option to
install the AWS CLI v2 as an add-on application in the `/opt` directory:
```
./configure --libdir=/opt
```
This command results in the AWS CLI v2 being installed at `/opt/aws-cli` and
the executables being installed at their default location of `/usr/local/bin`.
In addition, the `make install` rule supports:
* [`DESTDIR`](https://www.gnu.org/software/make/manual/html_node/DESTDIR.html#DESTDIR) variable - The path
to prepend to the configured installation prefix path when installing the AWS CLI. By default, no value is set
for this variable.
The `DESTDIR` variable allows users to install the AWS CLI to an alternative location to the finalized installation
location. For example, users can use the variable to install to a temporary location:
```
./configure --prefix=/usr/local
make
make DESTDIR=/tmp/stage install
```
These commands result in the AWS CLI v2 being installed at `/tmp/stage/usr/local/lib/aws-cli` and its
executables located in `/tmp/stage/usr/local/bin`.
##### Python interpreter
Through the [`AM_PATH_PYTHON`](https://www.gnu.org/software/automake/manual/html_node/Python.html)
Autoconf macro, the `./configure` script automatically selects a Python
interpreter installed on the system that is of version 3.8 or higher to use
in building and running the AWS CLI v2. The Python interpreter to use can
be explicitly set using the `PYTHON` environment variable when running the
`configure` script:
```bash
PYTHON=/path/to/python ./configure
```
##### Downloading dependencies
By default, it is required that all build and runtime dependencies of
the AWS CLI v2 are installed on the system. This includes any dependencies
that are Python libraries. All dependencies are checked when the `configure`
script is run, and if the system is missing any Python dependencies, the
`configure` script errors out. For example:
```
$ ./configure
checking for a Python interpreter with version >= 3.8... python3.8
checking for python3.8... /usr/local/bin/python3.8
checking for python3.8 version... 3.8
checking for python3.8 platform... darwin
checking for python3.8 script directory... ${prefix}/lib/python3.8/site-packages
checking for python3.8 extension module directory... ${exec_prefix}/lib/python3.8/site-packages
checking for --with-install-type... portable-exe
checking for --with-download-deps... Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/runpy.py", line 194, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "./scripts/build/__main__.py", line 71, in <module>
main()
File "./scripts/build/__main__.py", line 63, in main
validate(parsed_args.artifact)
File "./scripts/build/__main__.py", line 28, in validate
validate_env(artifact)
File "./scripts/build/validate_env.py", line 27, in validate_env
raise UnmetDependenciesException(unmet_deps)
validate_env.UnmetDependenciesException: Environment requires following Python dependencies:
awscrt (required: awscrt==0.11.13) (version installed: None)
configure: error: "Python dependencies not met"
```
Users can specify the `--with-download-deps` option to avoid having to install
all required Python dependencies themselves:
```
./configure --with-download-deps
```
In specifying this flag, the build process:
* Skips the configuration check to make sure all Python library dependencies
are installed on the system.
* During the `make` step, downloads **all** required dependencies and uses
**only** the downloaded dependencies to build the AWS CLI v2.
Currently, this flag only downloads Python packages, but may be expanded in
the future for non-Python dependencies.
##### Install type
The source install process supports two different installation types:
* `system-sandbox` - (Default) Creates an isolated Python virtual environment,
installs the AWS CLI v2 into the virtual environment, and symlinks to the
`aws` and `aws_completer` executable in the virtual environment.
* `portable-exe` - Freezes the AWS CLI v2 into a standalone executable that
can be distributed to environments of similar architectures. This is the
same process used to generate the official pre-built executables of the AWS
CLI v2.
The primary difference between the two installation types is that the
`portable-exe` freezes in a copy of the Python interpreter chosen in the
`configure` step to use for the runtime of the AWS CLI v2. This allows it to
be moved to other machines that may not have a Python interpreter.
While for the `system-sandbox`, the install of the AWS CLI v2 depends directly
on the selected Python interpreter for its runtime.
By default, the installation type is `system-sandbox`. To configure the
installation type, use the `--with-install-type` option and specify a value
of `portable-exe` or `system-sandbox`. For example:
```bash
./configure --with-install-type=portable-exe
```
For more information about the build details for these two installation types,
see the [Build/install mechanics section](#buildinstall-mechanics).
For more information on reasons to use one installation type over the over, see the
[Rationale section](#q-why-are-there-two-different-installation-types).
#### Supported make targets and usage
Once the `Makefile` is generated from the `configure` script, users can run a
variety of targets to manage the building and installing the AWS CLI v2 via
the command pattern:
```
make <target>
```
The supported targets are:
* `all` - Builds the AWS CLI v2 based on configuration. This is synonymous
to running `make` without a `<target>` argument.
* `install` - Installs the built AWS CLI v2 onto the system.
* `clean` - Removes all build artifacts from the `all` rule.
* `uninstall` - Uninstalls the AWS CLI v2 from the system.
Any other targets found in the `Makefile` are considered implementation details
and should not be used.
Below sections show how to use these targets to manage the installation of the
AWS CLI v2 beyond initially installing it.
##### Upgrade the AWS CLI v2
To upgrade the AWS CLI v2, users first re-download the latest source code
for the AWS CLI v2 and rerun the Autotools steps from the initial install
process:
```
./configure
make
make install
```
These steps completely remove any preexisting installation and replaces the
installation with the newly built version of the AWS CLI v2, assuming the same
installation configurations were used.
##### Uninstall AWS CLI v2
To remove the AWS CLI v2, users run:
```
make uninstall
```
Assuming the same `./configure` options were used in generating the
Makefile that installed the AWS CLI v2, this deletes both the installation of
the AWS CLI v2 and its symlinks in the `bindir` to its executables.
#### Backwards compatibility
In regard to backwards compatibility, these are the aspects of installing
from source that are backwards compatible:
* Autotools usage patterns for installing, upgrading, and uninstalling the
AWS CLI v2. For example, the commands to install/upgrade the
AWS CLI v2 will always be: `./configure`, `make`, and `make install`, and
the command to uninstall the AWS CLI v2 will always be `make uninstall`.
* Documented `configure` options.
* Documented `make` targets.
* Usage of `libdir` and `bindir` in the installation process. All bits
related to the AWS CLI v2 installation will be located in the `libdir` and
all publicly accessible executables (e.g., `aws` and `aws_completer`) will
be located in the `bindir`.
These are the aspects that have **no** backwards compatibility guarantees:
* Dependencies. The AWS CLI v2 will add new dependencies in the future. This
means users must install any new dependencies to their system in order to
install the AWS CLI v2 from source. This includes anything from:
* Increasing minimum required Python version
* Pulling in a new Python library dependency
* Requiring a new system dependency
Furthermore, the `--with-download-deps` option does not guarantee that all
possible new dependencies in the future will be accounted for by the flag. For
example, a new programming language may be required in the future
(e.g., Go, Rust) and the `--with-download-deps` option would likely not account
for that new requirement.
In general, users cannot make the assumption that when upgrading versions of
the AWS CLI v2, using the same environment and same build steps will
always result in a successful install. If building from source in a CI/CD
setting, users should pin to a specific version of the AWS CLI v2 code base
using repository tags or a versioned source distribution
(see [Hosted source distribution section](#hosted-source-distribution)) to
ensure automation does not break.
### Build/install mechanics
Below details the steps taken in building and installing the AWS CLI v2 from
source. Note the build directory in these steps refers to a directory that is
created in the same directory as the `Makefile` and hosts artifacts related to
the build.
#### Build steps
When running `make`, the following steps are run:
1. Use the [`venv`](https://docs.python.org/3/library/venv.html) module
built into the Python standard library to create a new virtual environment
in the build directory. The virtual environment is also bootstraped with
a [version of pip that is vendored in the Python standard library](https://docs.python.org/3/library/ensurepip.html).
2. If `--with-download-deps` was specified in the `configure` command, it
pip installs all Python packages required to build and run the AWS CLI v2.
This includes: `wheel`, `setuptools`, all CLI runtime dependencies, and
`pyinstaller` (if building the `portable-exe`). These requirements are all
specified in lock files generated from [`pip-compile`](https://github.com/jazzband/pip-tools).
If `--with-download-deps` was not specified in the `configure` command, it
copies all Python libraries from the Python interpreter's site package plus
any scripts (e.g., `pyinstaller`) into the virtual environment being used
for the build.
3. Run `pip install` directly on the AWS CLI v2 codebase to do an offline,
in-tree build and install of the AWS CLI v2 into the build virtual
environment. This is done by including the follow pip flags:
* [`--no-build-isolation`](https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-no-build-isolation)
* [`--no-cache-dir`](https://pip.pypa.io/en/stable/cli/pip_install/#caching)
* [`--no-index`](https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-no-index)
4. If the `--install-type` was set to `portable-exe` in the `configure`
command, run [`pyinstaller`](https://www.pyinstaller.org/) to build a
standalone executable.
#### Install steps
When running `make install`, the following steps are run:
1. Move the built virtual environment (if the install type is `system-sandbox`)
or standalone executable (if the install type is a `portable-exe`) to the
configured install directory (i.e., `<libdir>/awscli`).
2. Create symlinks for both the `aws` and `aws_completer` in the configured
bin directory (i.e., at `<bindir>/aws` and `<bindir>/aws_completer`).
### Provisional support for PEP 517
[PEP 517](https://www.python.org/dev/peps/pep-0517/) specifies a build-system
independent format for building Python packages. The AWS CLI v2 code base
is PEP 517 compliant in that a PEP 517 compliant build tool can build sdists
and wheels of the AWS CLI v2, which in turn can be used to install the
AWS CLI v2 onto a system. For example, users can build a wheel and install it
through pip:
```
pip wheel . --wheel-dir dist/
pip install dist/awscli-2.2.1-py3-none-any.whl
```
#### Meaning of "provisional support"
Provisional support means that PEP 517 compliance is maintained as a best
effort, and there is no guarantee that compliance will be maintained in the
future. Users should only directly rely on this functionality as a last resort
because its support is contingent on the implementation detail that the AWS
CLI is written in Python.
#### Required code base changes for PEP 517 support
To make the AWS CLI v2 codebase compliant, it requires the following changes:
* Introduce a `pyproject.toml` file (see [PEP 518](https://www.python.org/dev/peps/pep-0518/))
and in-tree build backend that builds the autocomplete index when building
both the sdist and wheel
(see [PEP 517](https://www.python.org/dev/peps/pep-0517/#in-tree-build-backends)).
* Port all information from the `setup.py` and `setup.cfg` to `pyproject.toml
that can be programmatically parsed for runtime dependencies.
* Pull in and maintain the unreleased `botocore` `v2` branch along with
`s3transfer` into the AWS CLI v2 codebase.
### Hosted source distribution
Users can install from source by either checking out the git repository or
by downloading a hosted source distribution of the AWS CLI v2.
The source distribution is a Python sdist generated from a PEP 517 compliant
build tool.
The source distribution of the latest version of the AWS CLI v2 is hosted at:
```
https://awscli.amazonaws.com/awscli.tar.gz
```
The source distribution of any particular version of the AWS CLI v2 is hosted
at:
```
https://awscli.amazonaws.com/awscli-<version>.tar.gz
```
where `<version>` is the literal version of the AWS CLI. For example, if a
user wants version `2.3.0`, they should download the source distribution at:
```
https://awscli.amazonaws.com/awscli-2.3.0.tar.gz
```
In addition, users can download detached PGP signatures for each hosted source
distribution by appending `.sig` to the artifact name. For example the
detached signature for the latest source distribution is hosted at:
```
https://awscli.amazonaws.com/awscli.tar.gz.sig
```
#### Sample usage
Below shows how a user can download and install version `2.3.0` of the AWS
CLI v2 from source using the hosted source distribution:
```bash
curl -O https://awscli.amazonaws.com/awscli-2.3.0.tar.gz
curl -O https://awscli.amazonaws.com/awscli-2.3.0.tar.gz.sig
gpg --verify awscli-2.3.0.tar.gz.sig awscli-2.3.0.tar.gz # Assuming public AWS CLI key is imported
tar -xf awscli-2.3.0.tar.gz
cd awscli-2.3.0
./configure
make
make install
```
## Rationale/FAQ
#### Q. What are the reasons for choosing Autotools for installing from source?
Autotools was chosen because it met all of [the goals in the motivation section](#goals).
Specifically:
* It specializes on portability and requires no additional dependencies for
POSIX environments. This should help maximize the number of
environments the AWS CLI v2 can be installed on. For systems that do not
have a POSIX-compatible shell (e.g., Windows), there is software available
to install to help run the scripts (e.g., MSYS2).
* Autotools is one of the most common build systems. This improves familiarity
for any users looking to install the AWS CLI v2 from source as Autotools
enabled projects follow the same `configure`, `make`, `make install` command
flow and share similar configuration flags.
* Autotools is language agnostic. It shields users from having to understand
Python build tool usage and details and provides stability if we needed to
change the underlying programming language and corresponding build tools.
#### Q. What alternatives to Autotools were considered?
These were some of the alternative options considered:
##### Cmake
Use [CMake](https://cmake.org/) as the entry point to building and installing
the AWS CLI v2 from source. See [Appendix B](#b-exploration-of-cmake) for
notes on what this interface would look like.
**Pros**
* It is language agnostic (e.g., can abstract over the underlying
programming language).
* It is a commonly used build tool.
* It supports a wide range of build systems. Unlike Autotools that can only
generate GNU Makefiles, CMake can target GNU Makefiles as well as common
Windows build systems such as NMake and Visual Studio.
* The CMake CLI has built-in commands that allows you to build and install the
project (e.g., `cmake --build` and `cmake --install`) without having to
directly use the underlying build system (e.g., `make`). Therefore, you could
use the exact same build and install commands on Linux as in on Windows
(without the use of MSYS2).
**Cons**
* It requires that a user has CMake installed on their system. Unlike `make`
which is likely to be pre-installed on a user's system, `cmake` is likely
not installed unless the user is already building projects that use `cmake`.
Furthermore, for Windows, users would still need to install
Microsoft Visual Studio in order to access build systems that `cmake` would
target (e.g., `nmake`).
* It introduces a new tool that users will have to know how to use in order to
build and install the AWS CLI. While we can provide quick getting started
instructions, there is still the possibility that users will have to learn
about CMake concepts such as cache variables and build system generators.
With Autotools, it is scoped to just running a single `configure` shell
script followed by `make` commands. From the end user's perspective, there
is no additional concepts/knowledge needed past that single usage pattern.
* If we want to take advantage of new features in CMake, we will have to force
users to upgrade to new versions of CMake. This is different from Autotools
where the authors generate the `configure` script so only the authors need
to upgrade their Autotools utilities to access new features.
**Verdict**
In general, Autotools and CMake are similar in terms of functionality and
usage patterns. Arguably, CMake offers more functionality such as offering
unified CLI commands to build/install projects and being able to target more
than just GNU Makefiles for build systems. However, with respect
to building/installing the AWS CLI from source, these tools are just providing
thin, familiar wrappers over Python-specific build/install logic; none of the
tools' core functionality around building C/C++ libraries is actually
leveraged. For the purpose of being a thin, familiar interface, Autotools is
advantageous over CMake because:
* Minimal dependencies required to use the build/install interface.
* The end user interface is more minimal as it is scoped to running a single
`configure` script followed by `make` commands. Users do not have to
potentially learn the usage and concepts for a new tool (e.g., `cmake`).
In addition, one important note is that the decision between Autotools and
CMake is **not** a one-way door. It is possible for a project to allow users to
build and install it using either Autotools or CMake. So, CMake support can
always be added in the future if needed.
##### Custom build/install script
Building and installing would be exposed through a custom shell script or
Makefile.
**Pros**
* It is language agnostic (e.g., can abstract over the underlying
programming language).
* Can have greater control over build and install interface instead of trying
to fit the interface into the patterns of an established build tool.
**Cons:**
* Does not bring the same potential familiarity as an Autotools/CMake
project for users new to the project. Users will have to learn a new
usage pattern.
* Anything custom-built would not be able to match the maintainability and
portability of a more mature build system (e.g., Autotools and CMake)
* Easier to deviate from conventions established by other build systems,
which could make it more difficult to understand how to customize the
build and install of the AWS CLI.
**Verdict:**
While this option gives similar benefits to Autotools and CMake, it still does
not match up to these options when compared to portability and immediate
familiarity users gained from using Autotools or CMake.
##### Only expose PEP 517 support
This would entail having users directly rely on PEP 517 compliant Python
tools to build and then install the AWS CLI v2.
**Pros**
* It reduces complexity of the project (e.g., we would not have to add
another layer of abstraction over the Python build logic)
* It introduces no new dependencies. Python is already required to
build the AWS CLI and it comes with `pip` which is PEP 517 compliant.
Also, the Python build tools generally have cross-platform support.
**Cons:**
* Requires users to be familiar with Python build and install tooling and
be familiar how to use them safely (e.g., not install the AWS CLI into
the global site packages).
* If we were to change programming languages or add new build steps, it
will require users to rewrite any build logic.
**Verdict**
This not a viable option as it only really meets one (i.e., the first goal) of
the three goals from the motivation section.
#### Q. Why are there two different installation types?
By having the two different installations types, we're able to provide
more flexibility in how to build and install the AWS CLI v2.
The `system-sandbox` provides a lightweight install mechanism to get the
AWS CLI v2 installed on a system, while following best Python practices by
sandboxing the installation in a virtual environment. This installation is
intended for users that want to install the CLI from source in the
most frictionless way possible and don't necessary want/care that the
installation is coupled to their installation of Python.
The `portable-exe` allows users to build the same pre-built artifact
that is used in the other official pre-built artifacts (e.g., MSI, PKG,
Linux pre-built ZIP). These types of builds are useful because:
* Users can ensure their installation of AWS CLI v2 is not coupled to their
system installation of Python.
* Users can distribute their build to other similar systems that may not have
Python installed.
In general, a user may want to use their own version of the pre-built artifact
instead of one of the official artifacts because:
* They want to customize the build (e.g., hand select what dependencies are
bundled into the executable).
* They have compliance/security reasons to not rely on executables built
by third-parties and want to be able to build it themselves.
#### Q. Why is `system-sandbox` the default installation type?
It is the easier, more straightforward way out of the two options to install
the AWS CLI v2. Ideally, when users come to install the AWS CLI v2 from
source, they should be able to run `./configure`, `make`, `make install` in
a minimal amount of cycles and get a working version of the AWS CLI v2 quickly.
With the `portable-exe` install, it utilizes a library called
[PyInstaller](https://www.pyinstaller.org/) to freeze the AWS CLI v2 and
Python interpreter into an executable. While generally users should be able
to install and use PyInstaller to build the AWS CLI v2 with minimal to no
friction, it can be tedious to figure out how to fix issues when the
PyInstaller install/build does not work whether:
* There is not a pre-compiled PyInstaller bootloader available compatible for
their environment and have to
[build the bootloader themselves](https://pyinstaller.readthedocs.io/en/stable/bootloader-building.html).
* The Python interpreter may need to be recompiled to enable it as a shared
library (e.g., compile with `--enable-shared` on Linux or
`--enable-framework` for Mac).
In general, the benefit of having the installation not requiring a system
Python is not worth the potential problems users will have to work through
when building the exe when:
* The source install already requires Python to be on the system to build the
AWS CLI v2.
* One of the main reasons users will be building from source is because there
is not an official pre-built artifact available for their environment.
However, these types of environments will likely be the ones where
users will have to build the PyInstaller bootloader themselves or not be even
[fully tested](https://github.com/pyinstaller/pyinstaller#untested-platforms),
and be more prone to running into the issues.
#### Q. Why have `--with-download-deps` flag?
It makes it simpler for users to build the AWS CLI from source, especially
those who are not familiar with the Python ecosystem. Without this flag,
users would have to learn how to install the appropriate Python libraries and
may do so in a way that can be detrimental to their environment setup such as
install packages into their global site packages directory, which can break
other system tools.
#### Q. Why is there provisional support for PEP 517?
By supporting PEP 517, it helps achieve the goal of maximizing the number
of environments that are able to install the AWS CLI v2 by offering a path
forward to build the AWS CLI v2 as a standard-compliant wheel and sdist.
In general, assuming there is a Python interpreter available, wheels and sdist
are the most minimal artifact required to install a Python package onto a
system. Thus, given the AWS CLI v2 is currently a pure Python package and
requires a Python interpreter for source installs, wheel and sdist support
provide a sharp, no-frills escape hatch for installing the AWS CLI v2 whether:
* The environment is a non-POSIX compliant system, and the user does not want
or is unable to use additional software (e.g., MSYS2) to be able to run
the Autotools workflow in order to install the AWS CLI v2.
* The user actually wants the AWS CLI v2 installed directly as part of
the global or user site-packages directory, which would help minimize the
number of copies of third-party Python packages managed on the system.
However, it is only supported at a provisional capacity because the fact that
the AWS CLI runs on Python is still considered an implementation detail. This
means there is no guarantee that there will not be a change to the AWS CLI
in the future that will force a break in compliance to PEP 517 (e.g., rewriting
the code base to be primarily a Rust or Go-based project) and not be
installable as a wheel/sdist.
#### Q: Why is a custom in-tree build backend being introduced?
Builds of the AWS CLI v2 include a SQLite index for performing faster
auto-completions. This index is a large, ever-increasing in size
(currently at 9 MB) binary file that generally must be regenerated for every
release (which is generally happens daily). Committing this index as part of
every release to the repository would make the size of the repository bloated
and eventually unmanageable over time.
Therefore, the custom in-tree backend allows for the auto-completion index
to be generated and injected as part of building the wheel and sdist. This
allows the AWS CLI v2 be installable from a wheel or sdist without needing to
run any additional steps/scripts nor committing the index to the repository.
#### Q: Why are copies of botocore and s3transfer being maintained in the AWS CLI source?
The AWS CLI v2 currently relies on an unreleased version of botocore that
contains all the breaking changes that needed to happen in botocore in
order to make the desired breaking changes in the AWS CLI. Prior to this
proposal, building of the AWS CLI v2 required checking out and installing
botocore at the appropriate commit in order to install the AWS CLI v2 from
source.
This unreleased version of botocore is being maintained as part of the AWS CLI
v2 codebase for the following reasons:
* It simplifies the building and installing of the AWS CLI v2 as it removes
the need to download, checkout, and install a specific commit of the
botocore source in order to install the AWS CLI v2.
* For users that leverage provisional support for PEP 517 to install the
AWS CLI v2, they do not need to be concerned about the unreleased backwards
incompatible version of botocore breaking their installation of other Python
packages that rely on an officially released version of botocore.
* The AWS CLI team maintains the unreleased botocore branch as a
fork of botocore specifically for the AWS CLI v2, and this is already a
significant amount of work. From a maintenance perspective, there is little
difference in effort between maintaining the logic in a branch in the
botocore repository or as part of the AWS CLI codebase.
* There is no timetable for releasing these changes in an official
major version bump of botocore. Pulling in the botocore fork into the AWS
CLI v2 codebase allows the AWS CLI team to make larger changes to the
fork while minimizing the potential unintended directional impact on a
future official major version bump of botocore. It is also worth noting
that in the future, the team may also be able to stop maintaining its fork
of botocore in favor of an officially released major version of botocore.
The reason s3transfer is being maintained as part of the AWS CLI v2
codebase because it has a direct dependency on botocore. This is specifically
problematic because:
* If s3transfer was not pulled in, it would automatically pull in the official
version of botocore, which would unnecessarily bloat the size of the
dependency closure.
* It ensures that any changes that are made to the AWS CLI v2 maintained
version of botocore is compatible with s3transfer interfaces.
However, in the future if s3transfer removes botocore as a direct dependency,
the AWS CLI v2 would no longer need to maintain a copy of s3transfer in its
codebase.
## Future considerations
### Adding more make targets
In the future, we may want to add support for more GNU
[standard make targets](https://www.gnu.org/prep/standards/html_node/Standard-Targets.html)
for better managing source installs such as:
* `dist` - Generates a source distribution that could be distributed similar
to the official hosted source distributions.
* `check` - Runs smoke tests on the built AWS CLI v2 to make sure the
AWS CLI v2 is working correctly before actually installing it to the system.
* `html`/`install-html` - Generates the HTML references and installs them
to the configured location on the system.
### Accounting for more dependencies
Currently, the `--with-download-deps` flag only downloads Python packages that
are required to run the AWS CLI. However, in the future, this could include
some optional dependencies used in running the CLI. For example:
* Pager (e.g., `less`) if not available on the system for redirecting command
output
* Any standalone executable plugins required for customized commands
such as the [Session Manager plugin](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html)
to use the `ssm start-session` command.
These could be either exposed via:
* Including them as part of default value when `--with-download-deps` is
specified.
* Adding more opt-in values options to the `--with-download-deps` flag
(e.g., `--with-download-deps=pager`).
* Adding completely separate flags for downloading these optional dependencies
that is completely separate from `-with-download-deps`
(e.g., `--with-download-pager`, `--with-download-plugins`).
## Appendix
### A. Examples of source installs on various environments
#### Windows
In order to install the AWS CLI v2 from source on Windows, additional software
is required because it does not come with a POSIX-compliant shell out of the
box. One option to install the AWS CLI from source is to use
[MSYS2](https://www.msys2.org/). It provides a collection of tools and
libraries to help build and install Windows software, especially
for POSIX-based scripting (e.g., Autotools).
To get started with MSYS2, follow these
[install and usage instructions](https://www.msys2.org/). In a CI setting,
MSYS2 can be installed and used in an [automated fashion](https://www.msys2.org/docs/ci/).
Below is a sample of the steps that can be automated if trying to build and
install the AWS CLI v2 from PowerShell using MSYS2:
```powershell
> $env:CHERE_INVOKING = 'yes' # Preserve the current working directory
> C:\msys64\usr\bin\bash -lc "PYTHON='C:\path\to\python.exe' ./configure --prefix='C:\Program Files\AWSCLI' --with-download-deps"
> C:\msys64\usr\bin\bash -lc "make"
> C:\msys64\usr\bin\bash -lc "make install"
> $Env:PATH += ";C:\Program Files\AWSCLI\bin\"
> aws --version
```
#### Alpine Linux
Below is an example Dockerfile that can be used to get a working
installation of the AWS CLI v2 in an Alpine Linux container as an
[alternative to pre-built binaries for Alpine](https://github.com/aws/aws-cli/issues/4685):
```dockerfile
FROM python:3.8-alpine AS builder
ENV AWSCLI_VERSION=2.2.1
RUN apk add --no-cache \
curl \
make \
cmake \
gcc \
g++ \
libc-dev \
libffi-dev \
openssl-dev \
&& curl https://awscli.amazonaws.com/awscli-${AWSCLI_VERSION}.tar.gz | tar -xz \
&& cd awscli-${AWSCLI_VERSION} \
&& ./configure --prefix=/opt/aws-cli/ --with-download-deps \
&& make \
&& make install
FROM python:3.8-alpine
RUN apk --no-cache add groff
COPY --from=builder /opt/aws-cli/ /opt/aws-cli/
ENTRYPOINT ["/opt/aws-cli/bin/aws"]
```
This image can be built, and the CLI invoked from a container similar to the
one that is built on Amazon Linux 2:
```
$ docker build --tag awscli-alpine .
$ docker run --rm -it awscli-alpine --version
aws-cli/2.2.1 Python/3.8.11 Linux/5.10.25-linuxkit source/x86_64.alpine.3 prompt/off
```
The final size of this image is 150 MB, which is less than half the size of the
official [AWS CLI Docker image](https://hub.docker.com/r/amazon/aws-cli).
### B. Exploration of CMake
Below shows a sample `CMakeLists.txt` to enable building the AWS CLI via
CMake:
```cmake
cmake_minimum_required(VERSION 3.20)
project(awscli NONE)
set(
DOWNLOAD_DEPS FALSE
CACHE BOOL "Whether to download all dependencies and use those when \
building the AWS CLI. If not specified, the dependencies \
(including all python packages) must be installed on your system."
)
set(
INSTALL_TYPE system-sandbox
CACHE STRING "Type of AWS CLI installation. Options are: \
system-sandbox and portable-exe. The default is system-sandbox"
)
set(
Python_EXECUTABLE ""
CACHE FILEPATH "Path to Python interepreter to use. If not set, cmake \
will find an appropriate Python intrepreter."
)
cmake_path(APPEND CMAKE_SOURCE_DIR scripts buildctl OUTPUT_VARIABLE BUILDCTL)
cmake_path(APPEND CMAKE_BINARY_DIR build OUTPUT_VARIABLE BUILD_DIR)
cmake_path(APPEND CMAKE_INSTALL_PREFIX lib OUTPUT_VARIABLE CMAKE_INSTALL_LIBDIR)
cmake_path(APPEND CMAKE_INSTALL_PREFIX bin OUTPUT_VARIABLE CMAKE_INSTALL_BINDIR)
find_package(Python 3.8...<3.10 REQUIRED)
if (NOT DOWNLOAD_DEPS)
set(DOWNLOAD_DEPS_FLAG "")
execute_process(
COMMAND "${Python_EXECUTABLE}" "${BUILDCTL}" validate-env --artifact "${INSTALL_TYPE}"
RESULT_VARIABLE RESULT
ERROR_VARIABLE ERROR_MSG
)
if(RESULT AND NOT RESULT EQUAL 0)
message(FATAL_ERROR "${ERROR_MSG}")
endif()
else()
set(DOWNLOAD_DEPS_FLAG "--download-deps")
endif()
add_custom_target(
_build
ALL "${Python_EXECUTABLE}" "${BUILDCTL}" build --artifact "${INSTALL_TYPE}" --build-dir "${BUILD_DIR}" "${DOWNLOAD_DEPS_FLAG}"
)
install(
CODE
"execute_process(
COMMAND
${Python_EXECUTABLE}
${BUILDCTL}
install
--build-dir ${BUILD_DIR}
--lib-dir ${CMAKE_INSTALL_LIBDIR}
--bin-dir ${CMAKE_INSTALL_BINDIR}
)"
)
add_custom_target(
uninstall
"${Python_EXECUTABLE}" "${BUILDCTL}" uninstall --lib-dir "${CMAKE_INSTALL_LIBDIR}" --bin-dir "${CMAKE_INSTALL_BINDIR}"
)
```
The entry point to using CMake is calling the `cmake` CLI:
```bash
$ cmake .
```
This is the equivalent to the Autotools `configure` script where the
command resolves configuration and generates a `Makefile` (assuming the
target build system is GNU Makefiles). From there, users can use `make`
to build and install the project:
```bash
$ make
$ make install
```
CMake CLI provides built-in commands that abstracts over the generated build
system that can be used to build and install the project instead:
```bash
$ cmake --build .
$ cmake --install .
```
Similar to Autotools, users can configure the build and install of the project.
Users do so by providing `-D` argument to the initial call to `cmake`. For
example, in the code snippet below, the `-D` argument sets the
`CMAKE_INSTALL_PREFIX` variable (i.e., `--prefix` argument for the `configure` script)
to customize where to install the AWS CLI:
```bash
$ cmake -DCMAKE_INSTALL_PREFIX=/opt/aws-cli/ .
```
Users can also specify custom parameters such as the `DOWNLOAD_DEPS` to
determine whether to download dependencies as part of the build process:
```bash
$ cmake -DDOWNLOAD_DEPS=True .
```
To list all configuration parameters, users can run the following:
```bash
$ cmake -LH
// Specify type of AWS CLI installation. Options are: system-sandbox and portable-exe. The default is system-sandbox
ARTIFACT_TYPE:STRING=system-sandbox
// Install path prefix, prepended onto install directories.
CMAKE_INSTALL_PREFIX:PATH=/usr/local
// Build architectures for OSX
CMAKE_OSX_ARCHITECTURES:STRING=
// Minimum OS X version to target for deployment (at runtime); newer APIs weak linked. Set to empty string for default value.
CMAKE_OSX_DEPLOYMENT_TARGET:STRING=
// The product will be built against the headers and libraries located inside the indicated SDK.
CMAKE_OSX_SYSROOT:STRING=
// Download all dependencies and use those when building the AWS CLI. If not specified, the dependencies (including all python packages) must be installed on your system.
DOWNLOAD_DEPS:BOOL=FALSE
// Type of AWS CLI installation. Options are: system-sandbox and portable-exe. The default is system-sandbox
INSTALL_TYPE:STRING=system-sandbox
// Path to Python interepreter to use. If not set, cmake will find an appropriate Python intrepreter.
Python_EXECUTABLE:FILEPATH=
```
|