summaryrefslogtreecommitdiff
path: root/libmisc
diff options
context:
space:
mode:
Diffstat (limited to 'libmisc')
-rw-r--r--libmisc/CMakeLists.txt5
-rw-r--r--libmisc/include/libmisc/fmt.h52
-rw-r--r--libmisc/include/libmisc/macro.h34
-rw-r--r--libmisc/include/libmisc/obj.h74
-rw-r--r--libmisc/tests/test_macro.c9
-rw-r--r--libmisc/tests/test_obj.c2
-rw-r--r--libmisc/tests/test_obj_nest.c2
-rwxr-xr-xlibmisc/wrap-cc186
8 files changed, 295 insertions, 69 deletions
diff --git a/libmisc/CMakeLists.txt b/libmisc/CMakeLists.txt
index c6405ad..07f154b 100644
--- a/libmisc/CMakeLists.txt
+++ b/libmisc/CMakeLists.txt
@@ -18,6 +18,11 @@ target_sources(libmisc INTERFACE
utf8.c
)
+target_compile_options(libmisc INTERFACE
+ -no-integrated-cpp
+ -wrapper "${CMAKE_CURRENT_SOURCE_DIR}/wrap-cc"
+)
+
add_lib_test(libmisc test_assert)
add_lib_test(libmisc test_assert_min)
add_lib_test(libmisc test_endian)
diff --git a/libmisc/include/libmisc/fmt.h b/libmisc/include/libmisc/fmt.h
index 6c04d99..135e48b 100644
--- a/libmisc/include/libmisc/fmt.h
+++ b/libmisc/include/libmisc/fmt.h
@@ -113,27 +113,27 @@ struct fmt_buf {
};
LO_IMPLEMENTATION_H(fmt_dest, struct fmt_buf, fmt_buf);
-#define fmt_snprint(buf, n, ...) ({ \
- struct fmt_buf _w = { .dat = buf, .cap = n }; \
- lo_interface fmt_dest w = lo_box_fmt_buf_as_fmt_dest(&_w); \
- fmt_print(w, __VA_ARGS__); \
- if (_w.len < _w.cap) \
- ((char *)_w.dat)[_w.len] = '\0'; \
- _w.len; \
+#define fmt_snprint(buf, n, ...) ({ \
+ struct fmt_buf _w = { .dat = buf, .cap = n }; \
+ lo_interface fmt_dest w = LO_BOX(fmt_dest, &_w); \
+ fmt_print(w, __VA_ARGS__); \
+ if (_w.len < _w.cap) \
+ ((char *)_w.dat)[_w.len] = '\0'; \
+ _w.len; \
})
-#define fmt_asprint(...) ({ \
- struct fmt_buf _w = {}; \
- lo_interface fmt_dest w = lo_box_fmt_buf_as_fmt_dest(&_w); \
- fmt_print(w, __VA_ARGS__); \
- while (_w.cap <= _w.len) { \
- _w.cap = _w.len + 1; \
- _w.len = 0; \
- _w.dat = realloc(_w.dat, _w.cap); \
- fmt_print(w, __VA_ARGS__); \
- } \
- ((char *)_w.dat)[_w.len] = '\0'; \
- _w.dat; \
+#define fmt_asprint(...) ({ \
+ struct fmt_buf _w = {}; \
+ lo_interface fmt_dest w = LO_BOX(fmt_dest, &_w); \
+ fmt_print(w, __VA_ARGS__); \
+ while (_w.cap <= _w.len) { \
+ _w.cap = _w.len + 1; \
+ _w.len = 0; \
+ _w.dat = realloc(_w.dat, _w.cap); \
+ fmt_print(w, __VA_ARGS__); \
+ } \
+ ((char *)_w.dat)[_w.len] = '\0'; \
+ _w.dat; \
})
/* justify ********************************************************************/
@@ -145,13 +145,13 @@ LO_IMPLEMENTATION_H(fmt_dest, struct fmt_buf, fmt_buf);
fmt_print_byte(w, fillchar); \
} while (0)
-#define fmt_print_rjust(w, width, fillchar, ...) do { \
- struct fmt_buf _discard = {}; \
- lo_interface fmt_dest discard = lo_box_fmt_buf_as_fmt_dest(&_discard); \
- fmt_print2(discard, __VA_ARGS__); \
- while (_discard.len++ < width) \
- fmt_print_byte(w, fillchar); \
- fmt_print2(w, __VA_ARGS__); \
+#define fmt_print_rjust(w, width, fillchar, ...) do { \
+ struct fmt_buf _discard = {}; \
+ lo_interface fmt_dest discard = LO_BOX2(fmt_dest, &_discard); \
+ fmt_print2(discard, __VA_ARGS__); \
+ while (_discard.len++ < width) \
+ fmt_print_byte(w, fillchar); \
+ fmt_print2(w, __VA_ARGS__); \
} while (0)
void fmt_print_base16_u8_(lo_interface fmt_dest w, uint8_t x);
diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h
index a2d4264..48f52e5 100644
--- a/libmisc/include/libmisc/macro.h
+++ b/libmisc/include/libmisc/macro.h
@@ -9,6 +9,8 @@
#include <libmisc/assert.h>
+/* C: syntax ******************************************************************/
+
#define LM_FORCE_SEMICOLON static_assert(1, "force semicolon")
#define LM_PARTIAL_SWITCH(VAL) \
@@ -17,14 +19,14 @@
switch (VAL) \
_Pragma("GCC diagnostic pop") \
-/* for function definitions */
+/* C: function definitions ****************************************************/
#define LM_UNUSED(argname)
#define LM_ALWAYS_INLINE [[gnu::always_inline]] inline
#define LM_NEVER_INLINE [[gnu::noinline]]
#define LM_FLATTEN [[gnu::flatten]]
-/* types */
+/* C: types *******************************************************************/
/* If it's a pointer instead of an array, then typeof(&ptr[0]) == typeof(ptr) */
#define _LM_IS_ARRAY(ary) (!__builtin_types_compatible_p(typeof(&(ary)[0]), typeof(ary)))
@@ -38,7 +40,7 @@
: NULL; \
})
-/* numeric */
+/* C: numeric *****************************************************************/
#define LM_CEILDIV(n, d) ( ((n)+(d)-1) / (d) ) /** Return ceil(n/d) */
#define LM_ROUND_UP(n, d) ( LM_CEILDIV(n, d) * (d) ) /** Return `n` rounded up to the nearest multiple of `d` */
@@ -46,12 +48,12 @@
#define LM_NEXT_POWER_OF_2(x) ( (x) ? 1ULL<<((sizeof(unsigned long long)*8)-__builtin_clzll(x)) : 1) /** Return the lowest power of 2 that is > x */
#define LM_FLOORLOG2(x) ((sizeof(unsigned long long)*8)-__builtin_clzll(x)-1) /** Return floor(log_2(x) */
-/* strings */
+/* CPP: strings ***************************************************************/
#define LM_STR(x) #x
#define LM_STR_(x) LM_STR(x)
-/* token pasting */
+/* CPP: token pasting *********************************************************/
#define LM_CAT2(a, b) a ## b
#define LM_CAT3(a, b, c) a ## b ## c
@@ -59,7 +61,7 @@
#define LM_CAT2_(a, b) LM_CAT2(a, b)
#define LM_CAT3_(a, b, c) LM_CAT3(a, b, c)
-/* macro arguments */
+/* CPP: macro arguments *******************************************************/
#define LM_FIRST(a, ...) a
#define LM_SECOND(a, b, ...) b
@@ -70,7 +72,7 @@
#define LM_EAT(...)
#define LM_EXPAND(...) __VA_ARGS__
-/* conditionals */
+/* CPP: conditionals **********************************************************/
#define LM_T xxTxx
#define LM_F xxFxx
@@ -82,7 +84,7 @@
#define _LM_IF__xxTxx(...) __VA_ARGS__ LM_EAT
#define _LM_IF__xxFxx(...) LM_EXPAND
-/* tuples */
+/* CPP: tuples ****************************************************************/
#define LM_IS_TUPLE(x) LM_IS_SENTINEL(_LM_IS_TUPLE x)
#define _LM_IS_TUPLE(...) LM_SENTINEL()
@@ -112,7 +114,7 @@
#define LM_TUPLES_HEAD(tuples) LM_EXPAND(LM_FIRST LM_EAT() (_LM_TUPLES_COMMA tuples))
#define LM_TUPLES_TAIL(tuples) LM_EAT tuples
-/* iteration */
+/* CPP: iteration *************************************************************/
/* The desire to support a high number of iterations is in competition
* with the desire for short compile times. 16 is the lowest
@@ -168,4 +170,18 @@
/** The same as LM_FOREACH_TUPLE(), but callable from inside of LM_FOREACH_TUPLE(). */
#define LM_FOREACH_TUPLE2(...) _LM_DEFER2(_LM_FOREACH_TUPLE_indirect)()(__VA_ARGS__)
+/* CPP: wrap-cc extensions ****************************************************/
+
+#ifdef __LIBMISC_ENHANCED_CPP__
+/**
+ * `LM_DEFAPPEND(macro, val)` is like `#define macro val`, but can (1)
+ * be used from inside of a macro, and (2) appends to a value if it is
+ * already defined with LM_DEFAPPEND. There are lots of edge-cases,
+ * don't get cute.
+ */
+#define LM_DEFAPPEND(macro, ...) __xx__LM_DEFAPPEND__xx__(#macro, #__VA_ARGS__) LM_FORCE_SEMICOLON
+#define LM_DEFAPPEND_(macro, ...) _LM_DEFAPPEND_(#macro, __VA_ARGS__)
+#define _LM_DEFAPPEND_(macrostr, ...) __xx__LM_DEFAPPEND__xx__(macrostr, #__VA_ARGS__) LM_FORCE_SEMICOLON
+#endif
+
#endif /* _LIBMISC_MACRO_H_ */
diff --git a/libmisc/include/libmisc/obj.h b/libmisc/include/libmisc/obj.h
index 6645db7..6afa391 100644
--- a/libmisc/include/libmisc/obj.h
+++ b/libmisc/include/libmisc/obj.h
@@ -30,10 +30,6 @@
*
* Use `lo_interface {iface_name}` as the type of this interface; it
* should not be a pointer type.
- *
- * If there are any LO_NEST interfaces, this will define a
- * `lo_box_{iface_name}_as_{wrapped_iface_name}(obj)` function for
- * each.
*/
#define LO_NEST(_ARG_child_iface_name) \
(lo_nest, _ARG_child_iface_name)
@@ -50,28 +46,48 @@
}; \
LM_FOREACH_TUPLE(_ARG_iface_name##_LO_IFACE, \
_LO_IFACE_PROTO, _ARG_iface_name) \
- extern int LM_CAT2_(_HIDDEN_BOGUS_, __COUNTER__)
+ LM_FORCE_SEMICOLON
-#define _LO_IFACE_VTABLE(_tuple_typ, ...) _LO_IFACE_VTABLE_##_tuple_typ(__VA_ARGS__)
-#define _LO_IFACE_VTABLE_lo_nest(_ARG_child_iface_name) const struct _lo_##_ARG_child_iface_name##_vtable *_lo_##_ARG_child_iface_name##_vtable; LM_FOREACH_TUPLE2(_ARG_child_iface_name##_LO_IFACE, _LO_IFACE_VTABLE2)
-#define _LO_IFACE_VTABLE_lo_func(_ARG_ret_type, _ARG_func_name, ...) _ARG_ret_type (*_ARG_func_name)(void * __VA_OPT__(,) __VA_ARGS__);
+#define _LO_IFACE_VTABLE(_tuple_typ, ...) _LO_IFACE_VTABLE_##_tuple_typ(__VA_ARGS__)
+#define _LO_IFACE_VTABLE_lo_nest(_ARG_child_iface_name) \
+ const struct _lo_##_ARG_child_iface_name##_vtable *_lo_##_ARG_child_iface_name##_vtable; \
+ LM_FOREACH_TUPLE2(_ARG_child_iface_name##_LO_IFACE, _LO_IFACE_VTABLE2)
+#define _LO_IFACE_VTABLE_lo_func(_ARG_ret_type, _ARG_func_name, ...) \
+ _ARG_ret_type (*_ARG_func_name)(void * __VA_OPT__(,) __VA_ARGS__);
#define _LO_IFACE_VTABLE_indirect() _LO_IFACE_VTABLE
#define _LO_IFACE_VTABLE2(...) _LM_DEFER2(_LO_IFACE_VTABLE_indirect)()(__VA_ARGS__)
-#define _LO_IFACE_PROTO(_ARG_iface_name, _tuple_typ, ...) _LO_IFACE_PROTO_##_tuple_typ(_ARG_iface_name, __VA_ARGS__)
-#define _LO_IFACE_PROTO_lo_nest(_ARG_iface_name, _ARG_child_iface_name) \
- LM_ALWAYS_INLINE static lo_interface _ARG_child_iface_name \
- box_##_ARG_iface_name##_as_##_ARG_child_iface_name(lo_interface _ARG_iface_name obj) { \
- return (lo_interface _ARG_child_iface_name){ \
- .self = obj.self, \
- .vtable = obj.vtable->_lo_##_ARG_child_iface_name##_vtable, \
- }; \
- }
+#define _LO_IFACE_PROTO(_ARG_iface_name, _tuple_typ, ...) _LO_IFACE_PROTO_##_tuple_typ(_ARG_iface_name, __VA_ARGS__)
+#define _LO_IFACE_PROTO_lo_nest(_ARG_iface_name, _ARG_child_iface_name) \
+ LM_DEFAPPEND(_LO_REGISTRY_##_ARG_child_iface_name, \
+ (lo_interface _ARG_iface_name, _LO_BOX_##_ARG_iface_name##_as_##_ARG_child_iface_name)); \
+ LM_DEFAPPEND(_LO_BOX_##_ARG_iface_name##_as_##_ARG_child_iface_name(obj), \
+ { .self = obj.self, .vtable = obj.vtable->_lo_##_ARG_child_iface_name##_vtable });
#define _LO_IFACE_PROTO_lo_func(_ARG_iface_name, _ARG_ret_type, _ARG_func_name, ...) \
/* empty */
/**
+ * `LO_BOX(iface_name, obj)` boxes `obj` as a `lo_interface
+ * iface_name`. `obj` must be one of:
+ *
+ * - A pointer to a value that implements `lo_interface iface_name`
+ * - An already-boxed instance of `lo_interface iface_name`
+ * - An already-boxed instance of another interface that
+ * `iface_name` inherits from.
+ */
+#define LO_BOX(_ARG_iface_name, obj) _Generic((obj), \
+ lo_interface _ARG_iface_name: obj \
+ LM_FOREACH_TUPLE(_LO_REGISTRY_##_ARG_iface_name, \
+ _LO_BOX, _ARG_iface_name, obj))
+#define LO_BOX2(_ARG_iface_name, obj) _Generic((obj), \
+ lo_interface _ARG_iface_name: obj \
+ LM_FOREACH_TUPLE2(_LO_REGISTRY_##_ARG_iface_name, \
+ _LO_BOX, _ARG_iface_name, obj))
+#define _LO_BOX(_ARG_iface_name, obj, typ, boxfn) \
+ , typ: (lo_interface _ARG_iface_name)boxfn(obj)
+
+/**
* `LO_NULL(iface_name)` is the null/nil/zero value for `lo_interface {iface_name}`.
*/
#define LO_NULL(_ARG_iface_name) ((lo_interface _ARG_iface_name){})
@@ -99,23 +115,17 @@
* file to declare that `{impl_type}` implements the `{iface_name}`
* interface with functions named `{impl_name}_{method_name}`.
*
- * This will also define a `lo_box_{impl_name}_as_{iface_name}(obj)`
- * function.
- *
* You must also call the LO_IMPLEMENTATION_C in a single .c file.
*/
-#define LO_IMPLEMENTATION_H(_ARG_iface_name, _ARG_impl_type, _ARG_impl_name) \
- /* Vtable. */ \
- extern const struct _lo_##_ARG_iface_name##_vtable \
- _lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable; \
- /* Boxing. */ \
- LM_ALWAYS_INLINE static lo_interface _ARG_iface_name \
- lo_box_##_ARG_impl_name##_as_##_ARG_iface_name(_ARG_impl_type *self) { \
- return (lo_interface _ARG_iface_name){ \
- .self = self, \
- .vtable = &_lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable, \
- }; \
- } \
+#define LO_IMPLEMENTATION_H(_ARG_iface_name, _ARG_impl_type, _ARG_impl_name) \
+ /* Vtable. */ \
+ extern const struct _lo_##_ARG_iface_name##_vtable \
+ _lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable; \
+ /* Boxing. */ \
+ LM_DEFAPPEND(_LO_REGISTRY_##_ARG_iface_name, \
+ (_ARG_impl_type *, _LO_BOX_##_ARG_impl_name##_as_##_ARG_iface_name)); \
+ LM_DEFAPPEND(_LO_BOX_##_ARG_impl_name##_as_##_ARG_iface_name(obj), \
+ { .self = obj, .vtable = &_lo_##_ARG_impl_name##_##_ARG_iface_name##_vtable }); \
LM_FORCE_SEMICOLON
/**
diff --git a/libmisc/tests/test_macro.c b/libmisc/tests/test_macro.c
index 5157820..6810005 100644
--- a/libmisc/tests/test_macro.c
+++ b/libmisc/tests/test_macro.c
@@ -178,5 +178,14 @@ int main() {
free(act_suffix);
}
+ printf("== LM_DEFAPPEND ===========================================\n");
+ LM_DEFAPPEND(mylist, a);
+ LM_DEFAPPEND(mylist,
+ b);
+ {
+ const char *str = LM_STR_(mylist);
+ test_assert(strcmp(str, "a b") == 0);
+ }
+
return 0;
}
diff --git a/libmisc/tests/test_obj.c b/libmisc/tests/test_obj.c
index 687ad4e..a13b8c9 100644
--- a/libmisc/tests/test_obj.c
+++ b/libmisc/tests/test_obj.c
@@ -53,7 +53,7 @@ int main() {
struct myclass obj = {
.a = MAGIC1,
};
- lo_interface frobber iface = lo_box_myclass_as_frobber(&obj);
+ lo_interface frobber iface = LO_BOX(frobber, &obj);
test_assert(LO_CALL(iface, frob) == MAGIC1);
test_assert(LO_CALL(iface, frob1, MAGIC2) == MAGIC2);
LO_CALL(iface, frob0);
diff --git a/libmisc/tests/test_obj_nest.c b/libmisc/tests/test_obj_nest.c
index d5e563e..ba5ac37 100644
--- a/libmisc/tests/test_obj_nest.c
+++ b/libmisc/tests/test_obj_nest.c
@@ -64,7 +64,7 @@ static ssize_t myclass_write(struct myclass *self, void *buf, size_t count) {
int main() {
struct myclass _obj = {};
- lo_interface read_writer obj = lo_box_myclass_as_read_writer(&_obj);
+ lo_interface read_writer obj = LO_BOX(read_writer, &_obj);
test_assert(LO_CALL(obj, write, "Hello", 6) == 6);
char buf[6] = {};
test_assert(LO_CALL(obj, read, buf, 3) == 3);
diff --git a/libmisc/wrap-cc b/libmisc/wrap-cc
new file mode 100755
index 0000000..e7a0b91
--- /dev/null
+++ b/libmisc/wrap-cc
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3
+# libmisc/wrap-cc - Wrapper around GCC to enhance the preprocessor
+#
+# Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+
+import os
+import subprocess
+import sys
+import typing
+
+
+def scan_tuple(
+ text: str, beg: int, on_part: typing.Callable[[str], None] | None = None
+) -> int:
+ assert text[beg] == "("
+ pos = beg + 1
+ arg_start = pos
+ parens = 1
+ instring = False
+ while parens:
+ c = text[pos]
+ if instring:
+ match c:
+ case "\\":
+ pos += 1
+ case '"':
+ instring = False
+ else:
+ match c:
+ case "(":
+ parens += 1
+ case ")":
+ parens -= 1
+ if on_part and parens == 0 and text[beg + 1 : pos].strip():
+ on_part(text[arg_start:pos])
+ case ",":
+ if on_part and parens == 1:
+ on_part(text[arg_start:pos])
+ arg_start = pos + 1
+ case '"':
+ instring = True
+ pos += 1
+ assert text[pos - 1] == ")"
+ return pos - 1
+
+
+def unquote(cstr: str) -> str:
+ assert len(cstr) >= 2 and cstr[0] == '"' and cstr[-1] == '"'
+ cstr = cstr[1:-1]
+ out = ""
+ while cstr:
+ if cstr[0] == "\\":
+ match cstr[1]:
+ case "n":
+ out += "\n"
+ cstr = cstr[2:]
+ case "\\":
+ out += "\\"
+ cstr = cstr[2:]
+ case '"':
+ out += '"'
+ cstr = cstr[2:]
+ else:
+ out += cstr[0]
+ cstr = cstr[1:]
+ return out
+
+
+def preprocess(all_args: list[str]) -> typing.NoReturn:
+ # argparse #################################################################
+ _args = all_args
+
+ def shift(n: int) -> list[str]:
+ nonlocal _args
+ ret = _args[:n]
+ _args = _args[n:]
+ return ret
+
+ arg0 = shift(1)[0]
+ common_flags: list[str] = []
+ output_flags: list[str] = []
+ positional: list[str] = []
+ while _args:
+ if len(_args[0]) > 2 and _args[0][0] == "-" and _args[0][1] in "IDU":
+ _args = [_args[0][:2], _args[0][2:], *_args[1:]]
+ match _args[0]:
+ # Mode
+ case "-E" | "-quiet":
+ common_flags += shift(1)
+ case "-lang-asm":
+ os.execvp(all_args[0], all_args)
+ # Search path
+ case "-I" | "-imultilib" | "-isystem":
+ common_flags += shift(2)
+ # Define/Undefine
+ case "-D" | "-U":
+ common_flags += shift(2)
+ # Optimization
+ case "-O0" | "-O1" | "-O2" | "-O3" | "-Os" | "-Ofast" | "-Og" | "-Oz":
+ common_flags += shift(1)
+ case "-g":
+ common_flags += shift(1)
+ # Output files
+ case "-MD" | "-MF" | "-MT" | "-dumpbase" | "-dumpbase-ext":
+ output_flags += shift(2)
+ case "-o":
+ output_flags += shift(2)
+ # Other
+ case _:
+ if _args[0].startswith("-"):
+ if _args[0].startswith("-std="):
+ common_flags += shift(1)
+ elif _args[0].startswith("-m"):
+ common_flags += shift(1)
+ elif _args[0].startswith("-f"):
+ common_flags += shift(1)
+ elif _args[0].startswith("-W"):
+ common_flags += shift(1)
+ else:
+ raise ValueError(f"unknown flag: {_args!r}")
+ else:
+ positional += shift(1)
+ if len(positional) != 1:
+ raise ValueError("expected 1 input file")
+ infile = positional[0]
+
+ # enhance ##################################################################
+
+ common_flags += ["-D", "__LIBMISC_ENHANCED_CPP__"]
+
+ text = subprocess.run(
+ [arg0, *common_flags, infile],
+ stdin=subprocess.DEVNULL,
+ stdout=subprocess.PIPE,
+ stderr=sys.stderr,
+ check=True,
+ text=True,
+ ).stdout
+
+ macros: dict[str, str] = {}
+
+ marker = "__xx__LM_DEFAPPEND__xx__"
+ pos = 0
+ while (marker_beg := text.find(marker, pos)) >= 0:
+ args: list[str] = []
+
+ def add_arg(arg: str) -> None:
+ nonlocal args
+ args.append(arg)
+
+ beg_paren = marker_beg + len(marker)
+ end_paren = scan_tuple(text, beg_paren, add_arg)
+
+ before = text[:marker_beg]
+ # old = text[marker_beg : end_paren + 1]
+ after = text[end_paren + 1 :]
+
+ assert len(args) == 2
+ k = unquote(args[0].strip())
+ v = unquote(args[1].strip())
+ if k not in macros:
+ macros[k] = v
+ else:
+ macros[k] += " " + v
+
+ text = before + after
+ pos = len(before)
+
+ common_flags += ["-D", marker + "=LM_EAT"]
+ for k, v in macros.items():
+ common_flags += ["-D", k + "=" + v]
+
+ # Run, for-real ############################################################
+ os.execvp(arg0, [arg0, *common_flags, *output_flags, infile])
+
+
+def main(all_args: list[str]) -> typing.NoReturn:
+ if len(all_args) >= 2 and all_args[0].endswith("cc1") and all_args[1] == "-E":
+ preprocess(all_args)
+ else:
+ os.execvp(all_args[0], all_args)
+
+
+if __name__ == "__main__":
+ main(sys.argv[1:])