From 267a58afee85fd4f981d54eac103f8472ffbe5a4 Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Thu, 5 Oct 2023 14:21:00 -0600 Subject: [PATCH 1/3] Add --all-units flag to single file script This flag will cause the script to act as if the `--units` flag had been populated with every unit that is known to the library. Under the hood, the script has a safety mechanism to make sure that we actually use every command line parameter in the script. This new parameter would run afoul of this mechanism, because it's mutually exclusive with the `--units` argument. Therefore, we use `--all-units` to populate `--units`, and then delete `--all-units`. --- tools/bin/make-single-file | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/tools/bin/make-single-file b/tools/bin/make-single-file index 586fd49a..ec054ec8 100755 --- a/tools/bin/make-single-file +++ b/tools/bin/make-single-file @@ -16,6 +16,7 @@ import argparse import datetime +import os import re import subprocess import sys @@ -45,7 +46,7 @@ def main(argv=None): transitively included files which are within the project, but we leave other `#include` directives (such as standard library headers) untouched. """ - args = parse_command_line_args(argv) + args = enumerate_units(parse_command_line_args(argv)) files = parse_files( filenames=filenames( main_files=args.main_files, units=args.units, include_io=args.include_io @@ -74,7 +75,15 @@ def parse_command_line_args(argv): parser.add_argument("main_files", nargs="*", help="The main files to aggregate") - parser.add_argument("--units", nargs="*", default=[], help="The units to include") + unit_group = parser.add_mutually_exclusive_group(required=False) + unit_group.add_argument( + "--units", nargs="*", default=[], help="The units to include" + ) + unit_group.add_argument( + "--all-units", + action="store_true", + help="Include all units (may slow compilation!)", + ) parser.add_argument( "--version-id", @@ -92,6 +101,20 @@ def parse_command_line_args(argv): return parser.parse_args() +def enumerate_units(args): + """ + Massage args object so that it's "as if" user had specified all units manually. + + This means that if `--all-units` is specified, we populate the `units` list + with every existing entry, and then delete `--all-units`. + """ + if args.all_units: + args.units = [f[:-3] for f in os.listdir("au/units/") if f.endswith('.hh')] + + del args.all_units + return args + + def parse_files(filenames): """ Create a `SourceFile` for each of the transitive includes of `main_file`. From 81d86116f39ed6b4739379e3164096b4f57bb049 Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Fri, 6 Oct 2023 13:45:53 -0600 Subject: [PATCH 2/3] Add automatic all-units single file builds These include some simple unit tests both to make sure they would build, and to make sure they have the required extra features. --- BUILD.bazel | 55 ++++++++++++++++++++++++++-- release/BUILD.bazel | 22 +++++++++++ release/au_all_units_hh_test.cc | 40 ++++++++++++++++++++ release/au_all_units_noio_hh_test.cc | 34 +++++++++++++++++ 4 files changed, 148 insertions(+), 3 deletions(-) create mode 100644 release/au_all_units_hh_test.cc create mode 100644 release/au_all_units_noio_hh_test.cc diff --git a/BUILD.bazel b/BUILD.bazel index 81f97b4f..8dac162b 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -29,6 +29,8 @@ py_binary( srcs = ["update_docs.py"], data = [ "mkdocs.yml", + ":au_all_units_hh", + ":au_all_units_noio_hh", ":au_hh", ":au_noio_hh", ] + glob(["docs/**"]), @@ -43,6 +45,8 @@ py_binary( srcs = ["mike_bin.py"], data = [ "mkdocs.yml", + ":au_all_units_hh", + ":au_all_units_noio_hh", ":au_hh", ":au_noio_hh", ] + glob(["docs/**"]), @@ -72,7 +76,7 @@ BASE_UNIT_STRING = " ".join(BASE_UNITS) GIT_ID_CMD = "cat bazel-out/stable-status.txt | grep STABLE_GIT_ID | sed 's/STABLE_GIT_ID \\(.*\\)/\\1/' | tr -d '\\n'" -CMD_ROOT = "$(location tools/bin/make-single-file) {extra_opts} --units {units} --version-id $$({id_cmd}) > $(OUTS)" +CMD_ROOT = "$(location tools/bin/make-single-file) {extra_opts} {units} --version-id $$({id_cmd}) > $(OUTS)" ################################################################################ # Release single-file package `au.hh` @@ -84,7 +88,7 @@ genrule( cmd = CMD_ROOT.format( extra_opts = "", id_cmd = GIT_ID_CMD, - units = BASE_UNIT_STRING, + units = "--units " + BASE_UNIT_STRING, ), stamp = True, tools = ["tools/bin/make-single-file"], @@ -106,7 +110,7 @@ genrule( cmd = CMD_ROOT.format( extra_opts = "--noio", id_cmd = GIT_ID_CMD, - units = BASE_UNIT_STRING, + units = "--units " + BASE_UNIT_STRING, ), stamp = True, tools = ["tools/bin/make-single-file"], @@ -118,3 +122,48 @@ cc_library( hdrs = ["docs/au_noio.hh"], visibility = ["//release:__pkg__"], ) + +################################################################################ +# Release single-file package `au_all_units.hh` + +genrule( + name = "au_all_units_hh", + srcs = ["//au:headers"], + outs = ["docs/au_all_units.hh"], + cmd = CMD_ROOT.format( + extra_opts = "", + id_cmd = GIT_ID_CMD, + units = "--all-units", + ), + stamp = True, + tools = ["tools/bin/make-single-file"], +) + +cc_library( + name = "au_all_units_hh_lib", + hdrs = ["docs/au_all_units.hh"], + visibility = ["//release:__pkg__"], +) + +################################################################################ +# Release single-file package `au_all_units_noio.hh` + +genrule( + name = "au_all_units_noio_hh", + srcs = ["//au:headers"], + outs = ["docs/au_all_units_noio.hh"], + cmd = CMD_ROOT.format( + extra_opts = "--noio", + id_cmd = GIT_ID_CMD, + units = "--all-units", + ), + stamp = True, + tools = ["tools/bin/make-single-file"], + visibility = ["//release:__pkg__"], +) + +cc_library( + name = "au_all_units_noio_hh_lib", + hdrs = ["docs/au_all_units_noio.hh"], + visibility = ["//release:__pkg__"], +) diff --git a/release/BUILD.bazel b/release/BUILD.bazel index 46136a6a..7c41b551 100644 --- a/release/BUILD.bazel +++ b/release/BUILD.bazel @@ -19,6 +19,28 @@ cc_library( hdrs = ["common_test_cases.hh"], ) +cc_test( + name = "au_all_units_hh_test", + size = "small", + srcs = ["au_all_units_hh_test.cc"], + deps = [ + ":common_test_cases", + "//:au_all_units_hh_lib", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "au_all_units_noio_hh_test", + size = "small", + srcs = ["au_all_units_noio_hh_test.cc"], + deps = [ + ":common_test_cases", + "//:au_all_units_noio_hh_lib", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "au_hh_test", size = "small", diff --git a/release/au_all_units_hh_test.cc b/release/au_all_units_hh_test.cc new file mode 100644 index 00000000..1e371e9a --- /dev/null +++ b/release/au_all_units_hh_test.cc @@ -0,0 +1,40 @@ +// Copyright 2022 Aurora Operations, Inc. +// +// 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. + +#include + +#include "docs/au_all_units.hh" +#include "gtest/gtest.h" + +// clang-format off +// +// This file textually includes all of the test cases which every ready-made +// single-file release should pass. It needs to go after all other includes. +#include "release/common_test_cases.hh" +// clang-format on + +namespace au { + +namespace { +template +std::string stream_to_string(const T &x) { + std::ostringstream oss; + oss << x; + return oss.str(); +} +} // namespace + +TEST(AuAllUnitsHh, PrintsValueAndUnitLabel) { EXPECT_EQ(stream_to_string(minutes(3)), "3 min"); } + +} // namespace au diff --git a/release/au_all_units_noio_hh_test.cc b/release/au_all_units_noio_hh_test.cc new file mode 100644 index 00000000..719b5e1d --- /dev/null +++ b/release/au_all_units_noio_hh_test.cc @@ -0,0 +1,34 @@ +// Copyright 2022 Aurora Operations, Inc. +// +// 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. + +#include + +#include "docs/au_all_units_noio.hh" +#include "gtest/gtest.h" + +// clang-format off +// +// This file textually includes all of the test cases which every ready-made +// single-file release should pass. It needs to go after all other includes. +#include "release/common_test_cases.hh" +// clang-format on + +namespace au { + +TEST(AuAllUnitsNoioHh, IncludesMoreObscureUnits) { + EXPECT_EQ(minutes(120), hours(2)); + EXPECT_EQ(fahrenheit_pt(32), celsius_pt(0)); +} + +} // namespace au From 54ebee522fed23729a4303866a6741bdfecfccdd Mon Sep 17 00:00:00 2001 From: Chip Hogg Date: Fri, 6 Oct 2023 17:52:18 -0600 Subject: [PATCH 3/3] Link to all-units files from main doc We provide an appropriate degree of discouragement for general use, and clarity around suitable use cases. The godbolt link is currently "broken" (it doesn't compile), but we expect it to get fixed automatically once this PR lands. --- docs/install.md | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/install.md b/docs/install.md index fed208c6..507421a3 100644 --- a/docs/install.md +++ b/docs/install.md @@ -50,7 +50,7 @@ Here's an overview of the tradeoffs involved. Unit selection - Base units only + Base units only
(or too many units) Any units desired Any units desired, without needing "reinstall" @@ -164,6 +164,24 @@ should get you any other unit you're likely to want. The units we include are: Again, we recommend following the directions in the next section to get _exactly_ the units you care about. +??? warning "Pre-built files with all units" + We also provide pre-built files with every unit the library knows about. + + We don't advertise this option widely, because the library's compile time slowdown is largely + proportional to the number of units included in a translation unit. Thus, not only will this + configuration be the slowest of all, but _it will get increasingly slower as the library gets + better over time_ (by supporting more and more units out of the box). + + Therefore, these files are only for use cases where _you don't care about compile time_. The + primary example is [the Compiler Explorer ("godbolt")](https://godbolt.org/z/687Ef4oqM). + + **If you don't care about compile times**, here are the files: + + - [`au_all_units.hh`](./au_all_units.hh) + - [`au_all_units_noio.hh`](./au_all_units_noio.hh) + (Same as above, but with `` support stripped out) + + #### Custom single file It's easy to package the library in a _custom_ single file with _exactly_ the units you need.