[ccache] [PATCH v5] add support for '@' parameters

Joel Rosdahl joel at rosdahl.net
Tue Aug 7 09:24:13 MDT 2012


The only problem I see with this version of the patch is that it
modifies orig_args, which is supposed to preserve the original
argument list for later usage in failed() if needed, so I applied your
patch and then made cc_process_args work on a copy of orig_args
instead.

Thanks!

-- Joel

On 7 August 2012 01:30, Andrew Boie <andrew.p.boie at intel.com> wrote:
> From: "Boie, Andrew P" <andrew.p.boie at intel.com>
>
> These indicate to the compiler that additional command line options
> should be read from a text file. If encountered, read the file,
> tokenize any arguments, and if any are found, do an in-place replacement
> of the '@' parameter with the arguments within the file.
>
> args_insert() added to insert a set of arguments into a position within
> another set of arguments.
>
> args_init_from_gcc_atfile() reads and processes the argument files using the
> quoting/escape conventions that GCC expects.
>
> Signed-off-by: Andrew Boie <andrew.p.boie at intel.com>
> ---
>  args.c           |  125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  ccache.c         |   21 ++++++++-
>  ccache.h         |    2 +
>  test/test_args.c |   65 ++++++++++++++++++++++++++++
>  4 files changed, 212 insertions(+), 1 deletion(-)
>
> diff --git a/args.c b/args.c
> index 13a3d37..068338c 100644
> --- a/args.c
> +++ b/args.c
> @@ -52,11 +52,136 @@ args_init_from_string(const char *command)
>  }
>
>  struct args *
> +args_init_from_gcc_atfile(const char *filename)
> +{
> +       struct args *args;
> +       char *pos, *argtext, *argpos, *argbuf;
> +       char quoting;
> +
> +       /* Used to track quoting state; if \0, we're not
> +        * inside quotes. Otherwise stores the quoting character
> +        * that started it, for matching the end quote */
> +       quoting = '\0';
> +
> +       if (!(argtext = read_text_file(filename, 0)))
> +               return NULL;
> +
> +       args = args_init(0, NULL);
> +       pos = argtext;
> +       argbuf = x_malloc(strlen(argtext) + 1);
> +       argpos = argbuf;
> +
> +       while (1) {
> +               switch (*pos) {
> +               case '\\':
> +                       pos++;
> +                       if (*pos == '\0')
> +                               continue;
> +                       break;
> +
> +               case '\"': case '\'':
> +                       if (quoting != '\0') {
> +                               if (quoting == *pos) {
> +                                       quoting = '\0';
> +                                       pos++;
> +                                       continue;
> +                               } else
> +                                       break;
> +                       } else {
> +                               quoting = *pos;
> +                               pos++;
> +                               continue;
> +                       }
> +               case '\n': case '\t': case ' ':
> +                       if (quoting)
> +                               break;
> +                       /* Fall through */
> +               case '\0':
> +                       /* end of token */
> +                       *argpos = '\0';
> +                       if (argbuf[0] != '\0')
> +                               args_add(args, argbuf);
> +                       argpos = argbuf;
> +                       if (*pos == '\0')
> +                               goto out;
> +                       else {
> +                               pos++;
> +                               continue;
> +                       }
> +               }
> +               *argpos = *pos;
> +               pos++;
> +               argpos++;
> +       }
> +out:
> +       free(argbuf);
> +       free(argtext);
> +       return args;
> +}
> +
> +struct args *
>  args_copy(struct args *args)
>  {
>         return args_init(args->argc, args->argv);
>  }
>
> +/* Insert all arguments in src into dest at position index.
> + * If replace is true, the element at dest->argv[index] is replaced
> + * with the contents of src and everything past it is shifted.
> + * Otherwise, dest->argv[index] is also shifted.
> + *
> + * src is consumed by this operation and should not be freed or used
> + * again by the caller */
> +void
> +args_insert(struct args *dest, int index, struct args *src, bool replace)
> +{
> +       int offset;
> +       int j;
> +
> +       /* Adjustments made if we are replacing or shifting the element
> +        * currently at dest->argv[index] */
> +       offset = replace ? 1 : 0;
> +
> +       if (replace)
> +               free(dest->argv[index]);
> +
> +       if (src->argc == 0) {
> +               if (replace) {
> +                       /* Have to shift everything down by 1 since
> +                        * we replaced with an empty list */
> +                       for (j = index; j < dest->argc; j++)
> +                               dest->argv[j] = dest->argv[j + 1];
> +                       dest->argc--;
> +               }
> +               args_free(src);
> +               return;
> +       }
> +
> +       if (src->argc == 1 && replace) {
> +               /* Trivial case; replace with 1 element */
> +               dest->argv[index] = src->argv[0];
> +               src->argc = 0;
> +               args_free(src);
> +               return;
> +       }
> +
> +       dest->argv = (char**)x_realloc(dest->argv,
> +                       (src->argc + dest->argc + 1 - offset) *
> +                       sizeof(char *));
> +
> +       /* Shift arguments over */
> +       for (j = dest->argc; j >= index + offset; j--)
> +               dest->argv[j + src->argc - offset] = dest->argv[j];
> +
> +       /* Copy the new arguments into place */
> +       for (j = 0; j < src->argc; j++)
> +               dest->argv[j + index] = src->argv[j];
> +
> +       dest->argc += src->argc - offset;
> +       src->argc = 0;
> +       args_free(src);
> +}
> +
>  void
>  args_free(struct args *args)
>  {
> diff --git a/ccache.c b/ccache.c
> index 8e36bdd..5792482 100644
> --- a/ccache.c
> +++ b/ccache.c
> @@ -1445,9 +1445,28 @@ cc_process_args(struct args *orig_args, struct args **preprocessor_args,
>                         goto out;
>                 }
>
> +               if (str_startswith(argv[i], "@")) {
> +                       char *argpath = argv[i] + 1;
> +                       struct args *file_args;
> +
> +                       file_args = args_init_from_gcc_atfile(argpath);
> +                       if (!file_args) {
> +                               cc_log("Coudln't read arg file %s", argpath);
> +                               stats_update(STATS_ARGS);
> +                               result = false;
> +                               goto out;
> +                       }
> +
> +                       args_insert(orig_args, i, file_args, true);
> +
> +                       argc = orig_args->argc;
> +                       argv = orig_args->argv;
> +                       i--;
> +                       continue;
> +               }
> +
>                 /* These are always too hard. */
>                 if (compopt_too_hard(argv[i])
> -                   || str_startswith(argv[i], "@")
>                     || str_startswith(argv[i], "-fdump-")) {
>                         cc_log("Compiler option %s is unsupported", argv[i]);
>                         stats_update(STATS_UNSUPPORTED);
> diff --git a/ccache.h b/ccache.h
> index 7e25883..a0a82aa 100644
> --- a/ccache.h
> +++ b/ccache.h
> @@ -70,11 +70,13 @@ struct args {
>
>  struct args *args_init(int, char **);
>  struct args *args_init_from_string(const char *);
> +struct args *args_init_from_gcc_atfile(const char *filename);
>  struct args *args_copy(struct args *args);
>  void args_free(struct args *args);
>  void args_add(struct args *args, const char *s);
>  void args_add_prefix(struct args *args, const char *s);
>  void args_extend(struct args *args, struct args *to_append);
> +void args_insert(struct args *dest, int index, struct args *src, bool replace);
>  void args_pop(struct args *args, int n);
>  void args_set(struct args *args, int index, const char *value);
>  void args_strip(struct args *args, const char *prefix);
> diff --git a/test/test_args.c b/test/test_args.c
> index 50608fc..8da83bd 100644
> --- a/test/test_args.c
> +++ b/test/test_args.c
> @@ -59,6 +59,31 @@ TEST(args_init_from_string)
>         args_free(args);
>  }
>
> +TEST(args_init_from_gcc_atfile)
> +{
> +       int fd;
> +       struct args *args;
> +       const char *argtext = "first sec\\\tond\tthi\\\\rd\nfourth  \tfif\\ th \"si'x\\\" th\" 'seve\nth'\\";
> +
> +       fd = open("gcc_atfile", O_CREAT | O_WRONLY, 0600);
> +       CHECK(fd >= 0);
> +       CHECK(write(fd, argtext, strlen(argtext)) == (ssize_t)strlen(argtext));
> +       close(fd);
> +
> +       args = args_init_from_gcc_atfile("gcc_atfile");
> +       CHECK(args);
> +       CHECK_INT_EQ(7, args->argc);
> +       CHECK_STR_EQ("first", args->argv[0]);
> +       CHECK_STR_EQ("sec\tond", args->argv[1]);
> +       CHECK_STR_EQ("thi\\rd", args->argv[2]);
> +       CHECK_STR_EQ("fourth", args->argv[3]);
> +       CHECK_STR_EQ("fif th", args->argv[4]);
> +       CHECK_STR_EQ("si'x\" th", args->argv[5]);
> +       CHECK_STR_EQ("seve\nth", args->argv[6]);
> +       CHECK(!args->argv[7]);
> +       args_free(args);
> +}
> +
>  TEST(args_copy)
>  {
>         struct args *args1 = args_init_from_string("foo");
> @@ -144,4 +169,44 @@ TEST(args_to_string)
>         args_free(args);
>  }
>
> +TEST(args_insert)
> +{
> +       struct args *args = args_init_from_string("first second third fourth fifth");
> +
> +       struct args *src1 = args_init_from_string("alpha beta gamma");
> +       struct args *src2 = args_init_from_string("one");
> +       struct args *src3 = args_init_from_string("");
> +       struct args *src4 = args_init_from_string("alpha beta gamma");
> +       struct args *src5 = args_init_from_string("one");
> +       struct args *src6 = args_init_from_string("");
> +
> +       args_insert(args, 2, src1, true);
> +       CHECK_STR_EQ_FREE2("first second alpha beta gamma fourth fifth",
> +                       args_to_string(args));
> +       CHECK_INT_EQ(7, args->argc);
> +       args_insert(args, 2, src2, true);
> +       CHECK_STR_EQ_FREE2("first second one beta gamma fourth fifth",
> +                       args_to_string(args));
> +       CHECK_INT_EQ(7, args->argc);
> +       args_insert(args, 2, src3, true);
> +       CHECK_STR_EQ_FREE2("first second beta gamma fourth fifth",
> +                       args_to_string(args));
> +       CHECK_INT_EQ(6, args->argc);
> +
> +       args_insert(args, 1, src4, false);
> +       CHECK_STR_EQ_FREE2("first alpha beta gamma second beta gamma fourth fifth",
> +                       args_to_string(args));
> +       CHECK_INT_EQ(9, args->argc);
> +       args_insert(args, 1, src5, false);
> +       CHECK_STR_EQ_FREE2("first one alpha beta gamma second beta gamma fourth fifth",
> +                       args_to_string(args));
> +       CHECK_INT_EQ(10, args->argc);
> +       args_insert(args, 1, src6, false);
> +       CHECK_STR_EQ_FREE2("first one alpha beta gamma second beta gamma fourth fifth",
> +                       args_to_string(args));
> +       CHECK_INT_EQ(10, args->argc);
> +
> +       args_free(args);
> +}
> +
>  TEST_SUITE_END
> --
> 1.7.9.5
>
> _______________________________________________
> ccache mailing list
> ccache at lists.samba.org
> https://lists.samba.org/mailman/listinfo/ccache


More information about the ccache mailing list